什么是中间件
中间件(Middleware)是处于操作系统和应用程序之间的软件
举例: 1,RMI(Remote Method Invocations, 远程调用) 2,Load Balancing(负载均衡,将访问负荷分散到各个服务器中) 3,Transparent Fail-over(透明的故障切换) 4,Clustering(集群,用多个小的服务器代替大型机) 5,Back-end-Integration(后端集成,用现有的、新开发的系统如何去集成遗留的系统) 6,Transaction事务(全局/局部)全局事务(分布式事务)局部事务(在同一数据库联接内的事务) 7,Dynamic Redeployment(动态重新部署,在不停止原系统的情况下,部署新的系统) 8,System Management(系统管理) 9,Threading(多线程处理) 10,Message-oriented Middleware面向消息的中间件(异步的调用编程) 11,Component Life Cycle(组件的生命周期管理) 12,Resource pooling(资源池) 13,Security(安全) 14,Caching(缓存)
基于消息中间件的分布式系统的架构
从上图中可以看出来,消息中间件的是 1:利用可靠的消息传递机制进行系统和系统直接的通讯 2:通过提供消息传递和消息的排队机制,它可以在分布式系统环境下扩展进程间的通讯。
消息中间件应用的场景
1:跨系统数据传递 2:高并发的流量削峰 3:数据的分发和异步处理 4:大数据分析与传递 5:分布式事务 比如你有一个数据要进行迁移或者请求并发过多的时候,比如你有10W的并发请求下订单,我们可以在这些订单入库之前,我们可以把订单请求堆积到消息队列中,让它稳健可靠的入库和执行。
消息中间件的核心组成部分
1:消息的协议 2:消息的持久化机制 3:消息的分发策略 4:消息的高可用,高可靠 5:消息的容错机制
消息队列协议
面试题:为什么消息中间件不直接使用http协议呢? 1: 因为http请求报文头和响应报文头是比较复杂的,包含了cookie,数据的加密解密,状态码,响应码等附加的功能,但是对于一个消息而言,我们并不需要这么复杂,也没有这个必要性,它其实就是负责数据传递,存储,分发就行,一定要追求的是高性能。尽量简洁,快速。 2:大部分情况下http大部分都是短链接,在实际的交互过程中,一个请求到响应很有可能会中断,中断以后就不会就行持久化,就会造成请求的丢失。这样就不利于消息中间件的业务场景,因为消息中间件可能是一个长期的获取消息的过程,出现问题和故障要对数据或消息就行持久化等,目的是为了保证消息和数据的高可靠和稳健的运行。
AMQP协议
AMQP:(全称:Advanced Message Queuing Protocol) 是高级消息队列协议。由摩根大通集团联合其他公司共同设计。是一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有RabbitMQ等。 特性: 1:分布式事务支持。 2:消息的持久化支持。 3:高性能和高可靠的消息处理优势。
AMQP协议的支持者:RabbitMQ、ACTIVEMQ
MQTT协议
MQTT协议:(Message Queueing Telemetry Transport)消息队列遥测传输协议
是IBM开放的一个即时通讯协议,物联网系统架构中的重要组成部分。 特点: 1:轻量 2:结构简单 3:传输快,不支持事务 4:没有持久化设计。 应用场景: 1:适用于计算能力有限 2:低带宽 3:网络不稳定的场景。
MQTT协议的支持者:RabbitMQ、ACTIVEMQ
OpenMessage协议
是近几年由阿里、雅虎和滴滴出行、Stremalio等公司共同参与创立的分布式消息中间件、流处理等领域的应用开发标准。 特点: 1:结构简单 2:解析速度快 3:支持事务和持久化设计。
OpenMessage协议的支持者:RocketMQ
Kafka协议
Kafka协议是基于TCP/IP的二进制协议。消息内部是通过长度来分割,由一些基本数据类型组成。 特点是: 1:结构简单 2:解析速度快 3:无事务支持 4:有持久化设计、
Kafka协议的支持者:Kafka
消息队列持久化
简单来说就是将数据存入磁盘,而不是存在内存中随服务器重启断开而消失,使数据能够永久保存。
把消息默认放在内存中是为了加快传输和消费的速度,存入磁盘是保证消息数据的持久化。
非持久消息:是指当内存不够用的时候,会把消息和数据转移到磁盘,但是重启以后非持久化队列消息就丢失。
RabbitMQ的持久化队列分为: 1:队列持久化 2:消息持久化 3:交换机持久化 不论是持久化的消息还是非持久化的消息都可以写入到磁盘中,只不过非持久的是等内存不足的情况下才会被写入到磁盘中。
ActiveMQ | RabbitMQ | Kafka | RocketMQ | |
---|---|---|---|---|
文件存储 | 支持 | 支持 | 支持 | 支持 |
数据库 | 支持 | / | / | / |
消息的分发策略
MQ消息队列有如下几个角色 1:生产者 2:存储消息 3:消费者 那么生产者生成消息以后,MQ进行存储,消费者是如何获取消息的呢?一般获取数据的方式无外乎推(push)或者拉(pull)两种方式,典型的git就有推拉机制,我们发送的http请求就是一种典型的拉取数据库数据返回的过程。而消息队列MQ是一种推送的过程,而这些推机制会适用到很多的业务场景也有很多对应推机制策略。
ActiveMQ | RabbitMQ | Kafka | RocketMQ | |
---|---|---|---|---|
发布订阅 | 支持 | 支持 | 支持 | 支持 |
轮询分发 | 支持 | 支持 | 支持 | / |
公平分发 | / | 支持 | 支持 | / |
重发 | 支持 | 支持 | / | 支持 |
消息拉取 | / | 支持 | 支持 | 支持 |
消息队列高可用和高可靠
高可用
所谓高可用:是指产品在规定的条件和规定的时刻或时间内处于可执行规定功能状态的能力。 当业务量增加时,请求也过大,一台消息中间件服务器的会触及硬件(CPU,内存,磁盘)的极限,一台消息服务器你已经无法满足业务的需求,所以消息中间件必须支持集群部署。来达到高可用的目的。
集群模式1 - Master-slave主从共享数据的部署方式
生产者讲消息发送到Master节点,所有的client都连接这个消息队列共享这块数据区域,Master节点负责写入,一旦Master挂掉,slave节点继续服务。从而形成高可用
集群模式2 - Master- slave主从同步部署方式
这种模式写入消息同样在Master主节点上,但是主节点会同步数据到slave节点形成副本,和zookeeper或者redis主从机制很类同。这样可以达到负载均衡的效果,如果消费者有多个这样就可以去不同的节点就行消费,以为消息的拷贝和同步会暂用很大的带宽和网络资源。在后续的rabbtmq中会有使用。
集群模式3 - 多主集群同步部署模式
和上面的区别不是特别的大,但是它的写入可以往任意节点去写入。
集群模式4 - 多主集群转发部署模式
解释:如果你插入的数据是broker-1中,元数据信息会存储数据的相关描述和记录存放的位置(队列)。 它会对描述信息也就是元数据信息就行同步,如果消费者在broker-2中进行消费,发现自己几点没有对应的消息,可以从对应的元数据信息中去查询,然后返回对应的消息信息,场景:比如买火车票或者黄牛买演唱会门票,比如第一个黄牛有顾客说要买的演唱会门票,但是没有但是他会去联系其他的黄牛询问,如果有就返回。
集群模式5 Master-slave与Breoker-cluster组合的方案
解释:实现多主多从的热备机制来完成消息的高可用以及数据的热备机制,在生产规模达到一定的阶段的时候,这种使用的频率比较高。
这么集群模式,具体在后续的课程中会进行一个分析和讲解。他们的最终目的都是为保证:消息服务器不会挂掉,出现了故障依然可以抱着消息服务继续使用。
反正终归三句话: 1:要么消息共享, 2:要么消息同步 3:要么元数据共享
高可靠
所谓高可靠:是指系统可以无故障低持续运行,比如一个系统突然崩溃,报错,异常等等并不影响线上业务的正常运行,出错的几率极低,就称之为:高可靠。 在高并发的业务场景中,如果不能保证系统的高可靠,那造成的隐患和损失是非常严重的。 如何保证中间件消息的可靠性呢?可以从两个方面考虑: 1:消息的传输:通过协议来保证系统间数据解析的正确性。 2:消息的存储可靠:通过持久化来保证消息的可靠性。
RabbitMQ的核心组成部分
AMQP生产者流转过程
AMQP生产者流转过程
核心概念: Server:又称Broker ,接受客户端的连接,实现AMQP实体服务。 安装rabbitmq-server Connection:连接,应用程序与Broker的网络连接 TCP/IP/ 三次握手和四次挥手 Channel:网络信道,几乎所有的操作都在Channel中进行,Channel是进行消息读写的通道,客户端可以建立对各Channel,每个Channel代表一个会话任务。 Message :消息:服务与应用程序之间传送的数据,由Properties和body组成,Properties可是对消息进行修饰,比如消息的优先级,延迟等高级特性,Body则就是消息体的内容。 Virtual Host 虚拟地址,用于进行逻辑隔离,最上层的消息路由,一个虚拟主机理由可以有若干个Exhange和Queueu,同一个虚拟主机里面不能有相同名字的Exchange Exchange:交换机,接受消息,根据路由键发送消息到绑定的队列。(不具备消息存储的能力) Bindings:Exchange和Queue之间的虚拟连接,binding中可以保护多个routing key. Routing key:是一个路由规则,虚拟机可以用它来确定如何路由一个特定消息。 Queue:队列:也成为Message Queue,消息队列,保存消息并将它们转发给消费者。
RabbitMQ的安装和使用
5种消息模式
http://www.macrozheng.com/#/reference/rabbitmq_start
这5种消息模式是构建基于RabbitMQ的消息应用的基础,一定要牢牢掌握它们。
简单模式
简单模式是最简单的消息模式,它包含一个生产者、一个消费者和一个队列。生产者向队列里发送消息,消费者从队列中获取消息并消费。
模式示意图
工作模式
工作模式是指向多个互相竞争的消费者发送消息的模式,它包含一个生产者、两个消费者和一个队列。两个消费者同时绑定到一个队列上去,当消费者获取消息处理耗时任务时,空闲的消费者从队列中获取并消费消息。
模式示意图
发布/订阅模式
发布/订阅模式是指同时向多个消费者发送消息的模式(类似广播的形式),它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去,两个队列绑定到交换机上去,生产者通过发送消息到交换机,所有消费者接收并消费消息。
路由模式
路由模式是可以根据路由键
选择性给多个消费者发送消息的模式,它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去,两个队列通过路由键
绑定到交换机上去,生产者发送消息到交换机,交换机通过路由键
转发到不同队列,队列绑定的消费者接收并消费消息。
通配符模式
通配符模式是可以根据路由键匹配规则
选择性给多个消费者发送消息的模式,它包含一个生产者、两个消费者、两个队列和一个交换机。两个消费者同时绑定到不同的队列上去,两个队列通过路由键匹配规则
绑定到交换机上去,生产者发送消息到交换机,交换机通过路由键匹配规则
转发到不同队列,队列绑定的消费者接收并消费消息。
*
:只能匹配一个单词;#
:可以匹配零个或多个单词。
rabbitmq和spring同属一个公司开放的产品,所以他们的支持也是非常完善,这也是为什么推荐使用rabbitmq的一个原因。
解耦、削峰、异步
同步异步的问题(串行)
串行方式:将订单信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端
并行方式 异步线程池
并行方式:将订单信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间
存在问题: 1:耦合度高 2:需要自己写线程池自己维护成本太高 3:出现了消息可能会丢失,需要你自己做消息补偿 4:如何保证消息的可靠性你自己写 5:如果服务器承载不了,你需要自己去写高可用
异步消息队列的方式
好处 1:完全解耦,用MQ建立桥接 2:有独立的线程池和运行模型 3:出现了消息可能会丢失,MQ有持久化功能 4:如何保证消息的可靠性,死信队列和消息转移的等 5:如果服务器承载不了,你需要自己去写高可用,HA镜像模型高可用。 按照以上约定,用户的响应时间相当于是订单信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍
流量的削峰
04、分布式事务的可靠消费和可靠生产 05、索引、缓存、静态化处理的数据同步 06、流量监控 07、日志监控(ELK) 08、下单、订单分发、抢票
RabbitMQ高级-过期时间TTL
1、概述
过期时间TTL表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取;过了之后消息将自动被删除。RabbitMQ可以对消息和队列设置TTL。目前有两种方法可以设置。
- 第一种方法是通过队列属性设置,队列中所有消息都有相同的过期时间。
- 第二种方法是对消息进行单独设置,每条消息TTL可以不同。
如果上述两种方法同时使用,则消息的过期时间以两者之间TTL较小的那个数值为准。消息在队列的生存时间一旦超过设置的TTL值,就称为dead message被投递到死信队列, 消费者将无法再收到该消息。
RabbitMQ高级-消息确认机制的配置
NONE值是禁用发布确认模式,是默认值 CORRELATED值是发布消息成功到交换器后会触发回调方法,如1示例 SIMPLE值经测试有两种效果,其一效果和CORRELATED值一样会触发回调方法,其二在发布消息成功后使用rabbitTemplate调用waitForConfirms或waitForConfirmsOrDie方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker;
RabbitMQ高级-死信队列
DLX,全称为Dead-Letter-Exchange , 可以称之为死信交换机,也有人称之为死信邮箱。当消息在一个队列中变成死信(dead message)之后,它能被重新发送到另一个交换机中,这个交换机就是DLX ,绑定DLX的队列就称之为死信队列。 消息变成死信,可能是由于以下的原因:
- 消息被拒绝
- 消息过期
- 队列达到最大长度
DLX也是一个正常的交换机,和一般的交换机没有区别,它能在任何的队列上被指定,实际上就是设置某一个队列的属性。当这个队列中存在死信时,Rabbitmq就会自动地将这个消息重新发布到设置的DLX上去,进而被路由到另一个队列,即死信队列。
要想使用死信队列,只需要在定义队列的时候设置队列参数 x-dead-letter-exchange
指定交换机即可。
流程
RabbitMQ运维-内存磁盘的监控
当内存使用超过配置的阈值或者磁盘空间剩余空间对于配置的阈值时,RabbitMQ会暂时阻塞客户端的连接,并且停止接收从客户端发来的消息,以此避免服务器的崩溃,客户端与服务端的心态检测机制也会失效。 如下图:
当出现blocking或blocked话说明到达了阈值和以及高负荷运行了。
RabbitMQ的内存换页
在某个Broker节点及内存阻塞生产者之前,它会尝试将队列中的消息换页到磁盘以释放内存空间,持久化和非持久化的消息都会写入磁盘中,其中持久化的消息本身就在磁盘中有一个副本,所以在转移的过程中持久化的消息会先从内存中清除掉。
默认情况下,内存到达的阈值是50%时就会换页处理。 也就是说,在默认情况下该内存的阈值是0.4的情况下,当内存超过0.4*0.5=0.2时,会进行换页动作。
比如有1000MB内存,当内存的使用率达到了400MB,已经达到了极限,但是因为配置的换页内存0.5,这个时候会在达到极限400mb之前,会把内存中的200MB进行转移到磁盘中。从而达到稳健的运行。
可以通过设置 vm_memory_high_watermark_paging_ratio
来进行调整
RabbitMQ的磁盘预警
当磁盘的剩余空间低于确定的阈值时,RabbitMQ同样会阻塞生产者,这样可以避免因非持久化的消息持续换页而耗尽磁盘空间导致服务器崩溃。
默认情况下:磁盘预警为50MB的时候会进行预警。表示当前磁盘空间第50MB的时候会阻塞生产者并且停止内存消息换页到磁盘的过程。 这个阈值可以减小,但是不能完全的消除因磁盘耗尽而导致崩溃的可能性。比如在两次磁盘空间的检查空隙内,第一次检查是:60MB ,第二检查可能就是1MB,就会出现警告。