1、什么是中间件?
中间件是处于操作系统和应用程序之间的软件。在使用中间件时,往往是一组中间件集成在一起,构成一个平台(包括开发平台和运行平台),但在这组中间件中必须要有一个通信中间件。即中间件=平台+通信,这个定义也限定了只有用于分布式系统才能称为中间件,同时还可以把它与支撑软件和实用软件区分开来。
1.1 特性
- 能够进行通讯
- 支持高可用
- 数据持久性
- 作为使用者的话,可以屏蔽底层操作系统的复杂性;如果作为开发者的话,就必须要了解tcp/ IP协议,以及如何完成底层操作系统的沟通、如何去使用的多线程
- 使用中间件技术可以屏蔽应用程序架构之间的局限性。比如用户系统使用java开发,订单系统使用go开发,支付系统通过php开发,通过使用中间件可以把这些技术给串联起来,从而达到一个更加稳健、缩短开发周期,也可以减少我们的维护成本的一个目的
1.2 什么时候使用中间件技术
在项目的架构和重构中,使用任何技术和架构的改变我们都需要谨慎斟酌和思考。也就是说,但选择这些技术的时候,要思考这些技术是否需要用到,具不具备这些特征。如果是一个刚创建的公司建议还是使用单体架构,最多加个缓存中间件即可,不要盲目追求新或者所谓的高性能,而追求的背后一定是业务的驱动和项目的驱动,因为一旦追求意味着你的学习成本,公司的人员架构以及服务器成本、维护和运维成本都会提高,关键的还是自己花时间和花精力去探讨和研究。
2、中间件技术及架构的概述
2.1 分布式消息中间件
- activemq
- rabbitmq
- Kafka
- rocketmq
2.1.1 场景
- 消息中间件监控数据
- 异步数据传输场景
- 削峰填谷场景
- 任务调度场景
- 海量数据同步场景
- 分布式事务场景
- 日志管理场景
- 大数据分析场景
2.2 负载均衡中间件
- nginx
- lvs负载均衡软件
- keepalive
- CDN
2.3 缓存中间件
- memcache
- redis
2.4 数据中间件
- my cat
- shardingJdbc
3、基于消息中间件的分布式系统的结构
3.1 单体架构
在企业开发中,大部分的初期架构都采用的是单体架构的模式进行的,二这种架构的特点就是把所以的业务和模块、源代码、静态资源文件等都放在一个工程中,如果其中的一个模块升级或者发生很小变动都会重新编译和重新部署项目,这种架构存在的问题就是:
- 耦合度太高。所以业务和模块都在一个项目中,如果一个模块出现问题,那么就需要对所有模块进行重新编译和发布
- 运维成本过高。
- 不易维护
- 服务器成本高
- 以及升级架构的复杂度也会增大
3.2 分布式架构
通俗说:就是一个请求由服务器端的多个模块协同处理完成
和单体架构不同的是,单体架构是一个请求发起jvm调度线程(确切的是tomcat线程池)分配线程thread来处理请求直到释放,而分布式系统是:一个请求由多个系统共同来协同完成的,jvm和环境可能是独立。用生存中来举例的话,单体架构就可说是一个小房子很快就能搞定,如果你想建设一个鸟巢或大的建筑,就必须要各个环节的协同和分布,这样的目的也是项目发展到后题的时候要去部署和思考的问题
缺点
- 学习成本高,技术栈很多
- 运维成本和服务器成本增高
- 人员的成本也会提高
- 项目的负载度也会上升
- 面临的错误和容错性也会成倍增加
- 占用的服务器端口和通讯的选择的成本高
- 安全性的考虑和因素逼迫可能选择RMI/MQ相关的服务器端通讯
优点
- 服务系统的独立,占用的服务器资源减少和占用的硬件成本减少,确切的说是:可以合理的分配服务资源,不造成服务器资源的浪费
- 系统的独立维护和部署,耦合度降低,可插拔性
- 系统的架构和技术栈的选择可以变得灵活(而不是单纯的选择java)
- 弹性的部署,不会造成平台因部署造成的瘫痪和停服的状态
2.6 选择中间件所需特性
- 是否能够进行通讯
- 是否能够可持久化
- 是否能够支持高可用
- 是否支持跨平台,也即为能够屏蔽系统之间的语言的差异
所以总结:消息中间件就是利用可靠的消息传递机制进行系统间的通讯,通过提供消息传递和消息的排队机制,它可以在分布式系统环境下扩展进程间的通讯。
3.3 消息中间件应用场景
- 跨系统数据传递
- 高并发的流量削峰
- 数据的分发和异步处理
- 大数据分析与传递
- 分布式事务
比如你有一个数据要进行迁移或者请求并发过多的时候,比如你有10w的并发请求下订单,我们可以在这些订单入库之前,把订单请求堆积到消息队列中,让它稳健的入库和执行。
3.4 消息中间件的本质及设计
3.4.1 本质
它是一种接受数据、接受请求、存储数据、发送数据的一种技术服务。
MQ消息队列:负责数据的传送和接受,存储和传递,所以性能要高于普通服务和技术。
3.4.2 消息中间件的核心组成部分
- 消息的协议
- 消息的持久化机制
- 消息的分发策略
- 消息的高可用、高可靠
- 消息的容错机制
4、消息队列协议
4.1 什么是协议
我们知道消息中间件其实就是负责数据的传递、存储和分发消费。数据存储和分发的过程中肯定要遵守某种约定俗成的协议,至于你是采用底层的TCP/IP,还是UDP协议还是其他的取决于构建,而这些约定俗成的规范称之为协议。
总结:协议就是系统之间共同约定的规范。
4.2 网络协议三要素
1、语法:语法是用户数据与控制信息的结构与格式以及数据出现顺序
2、语义:语义是解释控制信息每个部分的意义。它规定了需要发出何种控制信息,以及完成的动作与做出什么样的响应
3、时序:时序是对事件发生顺序的详细说明
比如用MQ发送一个信息,是以什么数据格式发送到队列中,然后每个部分的含义是什么,发送完毕以后执行的动作以及消费者消费消息的动作,消费完毕的响应结果和反馈是什么,然后按照对应的执行顺序进行处理。如果还是不理解:大家每天都在接触的http请求协议:
- 1.语法:http规定了请求报文和响应报文的格式
- 2.语义:客户端主动发请求称之为请求(这是一种定义,同时你发起的是get/post请求)
- 3.时序:一个请求对应一个响应(一定要先有请求再有响应,这个是时序)
而消息中间件采用的并不是http协议,而常见的消息中间件协议有:OpenWire、AMQP、MQIT、Kafka、OpenMessage协议。
面试题:为什么消息中间件不直接使用http协议?
1、因为http请求报文头和响应b报文头是比较复杂的,包含了cookie,数据的加密解密,状态吗,响应吗等附加的功能,但是对于一个消息而言,我们并不需要这么复杂,也没有这个必要性,它其实就是负责数据的传递、存储和分发就可以,一定要追求高性能,尽量简洁、快捷
2、大部分情况下http大部分是短链接,也即为在实际的交互过程中,一个请求的响应可能被中断,中断以后就不会进行持久化,就会造成请求丢失。这样就不利于消息中间件的业务场景。因为消息中间件可能是一个长期的获取消息的过程,出现问题和故障要对数据或消息进行持久化等,目的是为了保证消息和数据的高可靠和稳定的运行。
也即使用http协议请求如果被中断的话,不会进行数据的持久化操作,数据会被丢失。
4.3 AMQP协议
AMQP:(全称:Advanced Message Queuing Protocol)是高级消息队列协议。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议个一个开放标准,为面向消息中间件设计。基于此协议客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有rabbitmq等
特性:
1、分布式事务支持
2、消息的持久化支持
3、高性能和高可用的消息处理优势
5、消息队列持久化
5.1 什么是持久化?
简单来说就是把数据存放在磁盘中,不存到内存中
5.2 为什么要持久化?
防止数据或者服务器出现故障从而造成重启而出现的数据丢失
5.3 常见的持久化方式
通过消息队列比如kafka、rabbitmq、rocketmq、activemq(还可以进行数据库持久化)
6、消息的分发策略
MQ消息队列有如下几个觉得:
- 生产者
- 存储消息
- 消费者
那么生产者生成消息以后,mq进行存储,消费者如何获取消息?一般获取数据的方式是通过推和拉两种方式,典型的就是Git的推拉机制,我们发送的http请求就是一种典型的拉取数据库数据返回的过程。而消息队列mq是一种推送的过程,而这些推送机制会适用到很多的业务场景,同时也要很多对应推机制策略
6.1 为什么要使用消费策略
-
以生活为例,我在app下了一个订单,我们的系统和服务有很多,我们如何知道这个消息被哪个系统或者哪些服务消费,那这个时候就需要一个分发策略。也即为MQ中的消费策略。
-
在发送消息的过程中可能会出现异常,或者网络的抖动、故障等等造成消息的无法消费,比如用户在下订单时,订单系统出现故障,导致用户支付失败,那么这个时候就需要消息中间件的消息重试机制策略。也即支持出现问题和故障的情况,保证消息不丢失还可以进行重发。