什么是中间件
什么是中间件
我国企业从20世纪80年代开始就逐渐进行信息化建设,由于方法和体系的不成熟,以及企业业务的市场需求的不断变化,一个企业可能同时运行着多个不同的业务系统,这些系统可能基于不同的操作系统、不同的数据库、异构的网络环境。现在的问题是,如何把这些信息系统结合成一个有机地协同工作的整体,真正实现企业跨平台、分布式应用。中间件便是解决之道,它用自己的复杂换取了企业应用的简单。
中间件(Middleware)是处于操作系统和应用程序之间的软件,也有人认为它应该属于操作系统中的一部分。人们在使用中间件时,往往是一组中间件集成在一起,构成一个平台(包括开发平台和运行平台),但在这组中间件中必须要有一个通信中间件,即中间件+平台+通信,这个定义也限定了只有用于分布式系统中才能称为中间件,同时还可以把它与支撑软件和使用软件区分开来
中间件特点
为解决分布异构问题,人们提出了中间件(middleware)的概念。中间件是位于平台(硬件和操作系统)和应用之间的通用服务,如下图所示,这些服务具有标准的程序接口和协议。针对不同的操作系统和硬件平台,它们可以有符合接口的协议规范的多种实现。

也很难给中间件一个严格的定义,但中间件应具有如下的一些特点:
(1)满足大量应用的需要
(2)运行于多种硬件和 OS平台
(3)支持分布计算,提供跨网络、硬件和 OS平台的透明性的应用或服务的交互
(4)支持标准的协议
(5)支持标准的接口
由于标准接口对于可移植性和标准协议对于互操作性的重要性,中间件已成为许多标准化工作的主要部分。对于应用软件开发,中间件远比操作系统和网络服务更为重要,中间件提供的程序接口定义了一个相对稳定的高层应用环境,不管底层的计算机硬件和系统软件怎样更新换代,只要将中间件升级更新,并保持中间件对外的接口定义不变,应用软件几乎不需任何修改,从而保护了企业在应用软件开发和维护中的重大投资。
简单说:中间件有个很大的特点,是脱离于具体设计目标,而具备提供普遍独立功能需求的模块。这使得中间件一定是可替换的。如果一个系统设计中,中间件时不可替代的,不是架构、框架设计有问题,那么就是这个中间件,在别处可能是个中间件,在这个系统内是引擎。
常见中间件

学习中间件的方式和技巧
1)理解中间件在项目架构中的作用,以及各中间件的底层实现
2)可以使用一些类比的生活概念去理解中间件
3)使用一些流程图或者脑图的方式去梳理各个中间件在架构中的作用
4)尝试用 java技术去实现中间件的原理
5)静下来去思考中间件在项目中设计的和使用的原因
6)如果找到对应的代替总结方案
7)尝试编写博文总结类同中间件技术的对比和使用场景
8)学会查看中间件的源码以及开源项目和博文
什么是消息中间件
什么是消息中间件
消息中间件:
是利用高效可靠的消息传递机制进行异步的数据传输,并基于数据通信进行分布式系统的集成。通过提供消息队列模型和消息传递机制,可以在分布式环境下扩展进程间的通信。
为什么需要使用消息中间件
具体地说,中间件屏蔽了底层操作系统的复杂性,使程序开发人员面对一个简单而统一的开发环境,减少程序设计的复杂性,将注意力集中在自己的业务上,不必再为程序在不同系统软件上的移植而重复工作,从而大大减少了技术上的负担,中间件带给应用系统的,不只是开发的简便、开发周期的缩短,也减少了系统的维护、运行和管理的工作量,还减少了计算机总体费用的投入。
消息中间件功能与组成
功能
消息中间件:
是一种接受数据、接受请求、存储数据、发送数据等功能的技术服务。
MQ消息队列:负责数据的接受,存储和传递,所以性能要高于普通服务和技术。
谁来生产消息,存储消息和消费消息呢?
生产者生产消息,MQ存储消息,消费者消费消息
核心组成部分
消息中间件的核心组成部分:
消息的协议
消息的持久化机制
消息的分发策略
消息的高可用
高可靠消息的容错机制
消息中间件应用场景
参考:https://www.jianshu.com/p/3fed7e963a2d
异步通信
异步通信:(异步处理)
当有些业务不想也不需要立即处理,消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它,然后在需要的时候再去处理它们。
案例讲解:
假设有一个系统调用链路为A调用B耗时20ms,B调用C耗时20ms,而C调用D需要2s,这样下来整个调用需要耗时2040ms。但实际上A调用B,B调用C只需要40ms,而D系统的引入直接导致系统性能下降约50倍。此时我们应该考虑将D系统的调用抽离出来,做一个异步调用。
生活中有一个很形象的例子。我们点一杯奶茶,下单、付款、通知商家制作都很快,然而到匹配外卖小哥配送这个过程很慢。作为用户来说,匹配外卖小哥这个过程延迟一些时间是可以接受的,只要我能快速下单成功,并且在一定时间范围内安排快递小哥送货即可。
按照上面的思路,系统A到系统B再到系统C就直接结束了,然后系统C再将消息发送到消息中间件中,系统D从消息中间件里取消息进行消费,这样子我们系统的性能就提高了接近50倍。
过程如下图所示:
系统解耦
系统解耦:降低系统之间的耦合度。
案例讲解:
首先假设有一个核心系统A,其能产生核心数据供下游服务(系统B和系统C)使用。此时最易想到的办法就是A直接把数据发送给B和C,流程如下:
那么问题来了,此时假设又有D、E、F、G等多个系统也需要使用核心数据,此时流程图如下:
我们可以想象一下,假设有上百个系统都需要系统A的核心数据,此时负责系统A的工程师将是崩溃的,一旦有系统加入,A系统就需要修改代码,将数据发送到新加入的系统。反之,如果有系统不再需要A发送数据,那么A系统又得修改代码不再向其发送数据。这样的架构设计耦合度太高了,我们就可以引入消息中间件来实现系统之间的解耦。即核心系统A生产核心数据,然后将核心数据发送到消息中间件,下游消费系统根据自身需求从中间件里获取消息进行消费,当不再需要数据时就不取消息进即可,这样系统之间耦合度就大大降低了。具体流程图如下:
流量削峰
流量消峰:
针对某一时间段的大量用户访问产生的大量流量,进行延缓,层层过滤,遵从 “最后落地到数据库的请求数要尽量少”的原则.
案例讲解:
假设有一个系统,正常时间也就每秒几百个请求,部署在一个8核16G的机器上,运行起来轻松加愉快。然而突然由于搞一个活动,高峰期请求数达到了几千,出现了瞬时流量高峰,此时最易想到的是加机器,部署个10台机器,也能扛住此时的高并发。
那么问题来了,瞬时流量每天也就那么几十分钟,过后就是正常的每秒几百请求,我们如果部署10台机器,那么平均下来没台机器的请求数也就每秒几十次,这样是不是有点太浪费资源了呢?大部分时候,每秒几百请求,一台机器就能够扛住了,但是为了抗那每天瞬时的高峰,硬是部署了10台机器,每天就那几十分钟有用,别的时候都是浪费资源的。
但是如果仅仅部署一台机器,瞬间高峰就会击垮系统,因为单台机器是不能扛住每秒几千次请求的。这时我们就可以考虑引入消息中间件,进行流量削峰。我们可以部署一层消息队列在机器前面,平时正常的每秒几百次请求,机器就正常的消费消息即可,一旦流量高峰到达时,大量消息会堆积在消息队列里面,机器只需要按照自己的最大负荷从消息队列里面消费,等流量高峰过了,慢慢地队列里面的消息也消费完毕了。此时达到了一个削峰填谷的作用。具体如图所示:
常见的消息中间件
ActiveMQ,RabbitMQ,Kafka,RocketMQ
消息队列协议
什么是协议

所谓协议是指:
1)计算机底层操作系统和应用程序通讯时共同遵守的一组约定,只有遵循共同的约定和规范,系统和底层操作系统之间才能相互交流
2)和一般的网络应用程序的不同它主要负责数据的接受和传递,所以性能比较的高
3)协议对数据格式和计算机之间交换数据都必须严格遵守规范
网络协议的三要素
1)语法:语法是用户数据与控制信息的结构与格式,以及数据出现的顺序
2)语义:语义是解释控制信息每个部分的意义,它规定了需要发出何种控制信息,以及完成的动作与做出什么样的响应
3)时序:时序是对事件发生顺序的详细说明
比如我 MQ发送一个信息,是以什么数据格式发送到队列中,然后每个部分的含义是什么,发送完毕以后的执行的动作,以及消费者消费消息的动作,消费完毕的相应结构和反馈是什么,然后按照对应的执行顺序进行处理。如果你还是不理解:大家每天都在接触的http请求协议:
1)语法:http规定了请求报文和响应报文的格式
2)语义:客户端主动发起请求称之为请求(这是一种定义,同时你发起的是 post/get请求)
3)时序:一个请求对应一个响应(一定先有请求在有响应,这个是时序)
常见的消息中间件协议
消息中间件采用的不是 http协议。
常见的消息中间件协议有:AMQP、Kafka,OpenMessage,OpenWire,MQTT协议
AMQP协议
AMQP:(全称:Advanced Message Queuing Protocol)是高级消息队列协议。由摩根大通集团联合其他公司共同设计。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
特性:
1)分布式事务支持
2)消息的持久化支持
3)高性能和高可靠的消息处理优势
支持MQ:RabbitMQ
MQTT协议
MQTT:(Message Queueing Telemetry Transport)消息队列是 IBM开放的及时通讯协议,物联网系统架构中的重要组成部分。
特点:
1)轻量
2)结构简单
3)传输快,不支持事务
4)没有持久化设计
支持MQ:RabbitMQ
Kafka协议
Kafka协议:是基于TCP/IP的二进制协议。消息内部是 通过长度来分割,由一些基本数据类型组成。
特点:
1)结构简单
2)解析速度快
3)无事务支持
4)有持久化设计
代表MQ:Kafka
OpenMessage协议
OpenMessage协议:是近几年由阿里、雅虎和滴滴出行、Stremalio等公司共同参与创立的分布式信息中间件、流处理等领域的应用开发标准。
特点:
1)结构简单
2)解析速度快
3)支持事务和持久化设计
支持MQ:RocketMQ
为什么消息中间件不使用 http协议
为什么消息中间件不使用 http协议?
1)因为 http请求报文头和响应报文头是比较复杂的,包含了Cookie,数据的加密解密,窗台吗,响应码等附加的功能,但是对于一个消息而言,我们并不需要这么复杂,也没有这个必要性,它其实就是负责数据传递,存储,分发就行,一定要追求的是高性能。尽量简洁,快速
2)大部分情况下 http大部分都是短链接,在实际的交互过程中,一个请求到响应都很有可能会中断,中断以后就不会执行持久化,就会造成请求的丢失。这样就不利于消息中间件的业务场景,因为消息中间件可能是一个长期的获取信息的过程,出现问题和故障要对数据或消息执行持久化等,目的是为了保证消息和数据的高可靠和稳健的运行。
消息队列持久化
持久化
简单来说就是将数据存入磁盘,而不是存在内存中随服务器重启断开而消失,使数据能够永久保存。
常见MQ的持久化方式
ActiveMQ:支持文件存储,支持数据库
RabbitMQ & Kafka & RocketMQ:支持文件存储
消息的分发策略
场景分析
场景分析一:
比如我在 APP上下了一个订单,我们的系统和服务很多,我们如何得知这个消息被哪个系统或者哪些服务器或者系统进行消费,那这个时候就需要一个分发的策略。这就需要消费策略。或者称之为消费的方法论。
场景分析二:
在发送消息的过程中可能会出现异常,或者网络的抖动,故障等等因为造成消息的无法消费,比如用户在下订单,消费 MQ接受,订单系统出现故障,导致用户支付失败,那么这个时候就需要消息中间件就必须支持消息重试机制策略。也就是支持:出现问题和故障的情况下,消息不丢失还可以进行重发消息策略的机制。
消息的分发策略
MQ消息队列有如下几个角色
1)生产者
2)存储消息
3)消费者
那么生产者生成消息以后,MQ进行存储,消费者是如何获取消息的呢?一般获取数据的方式无外乎推(push)或者拉(pull)两种方式,典型的 git就有推拉机制,我们发送的 http请求就是一种典型的拉取数据库数据返回的过程。而消息队列 MQ是一种推送的过程,而这些推机制会使用到很多的业务场景也有很多对应推机制策略。
消息队列高可用和高可靠
什么是高可用机制
所谓高可用:是指产品在规定的条件和规定的时刻或时间内处于可执行规定功能状态的能力
当业务量增加时,请求也过大,一台消息中间件服务器的会触及硬件(CPU,内存,磁盘)的极限,一台消息服务器你已经无法满足业务的需求,所以消息中间件必须支持集群部署,来达到高可用的目的。
集群模式一
Master-slave主从同步部署方式
解释:这种模式写入消息同样在 Master主节点上,但是主节点会同步数据到 slave节点形成副本,和 zookeeper或者 redis主从机制很雷同。这样可以达到负载均衡的效果,如果消费者有多个这样就可以去不同的节点进行消费,消息的拷贝和同步会占用很大的带宽和网络资源。
集群模式二
Master-slave与 Broker-cluster组合的方案
解释:如果你插入的数据是 broker-1中国,元数据信息会存储数据的相关描述和记录存放的位置(队列)。它会对描述信息也就是元数据信息进行同步,如果消费者在 broker-2中进行消费,发现自己节点没有对应的信息,可以从对应的元数据信息中去查询,然后返回对应的消息信息,场景:比如买火车票或者黄牛买演唱会门票,比如第一个黄牛有顾客说要买的演唱会门票,但是没有但是他回去联系其他的黄牛询问,如果有就返回。
注意:实现多主多从的热备机制来完成消息的高可用以及数据的热备机制,在生产规模达到一定的阶段的时候,这种使用的频率比较高。
什么是高可靠机制
所谓高可靠是指:
系统可以无故障低持续运行,比如一个系统突然崩溃,报错,异常等等并不影响线上业务的正常运行,出错的几率极低,就称之为:高可靠。
如何保证中间件消息的可靠性呢,可以从两个方面考虑:
1)消息的传输:通过协议来保证系统间数据解析的正确性
2)消息的存储区可靠:通过持久化来保证消息的可靠性
注意:在高并发的业务场景中,如果不能保证系统的高可靠,那造成的隐患和损失是非常严重的。