RabbitMQ
前言
很早就想要学习一种MQ了,RabbitMQ是一个很好的切入点
如果有些知识点认识错误,欢迎指出。
系列
同步异步(wx.request+ajax)
消息队列的学习与理解
消息队列之RabbitMQ的学习
RabbitMQ的应用之spring-boot-starter-amqp
选型
关于MQ中间件的选型,一直在纠结,即使早已撇开重量级的kafka以及轻量级的ActiveMQ,Rocket和RabbitMQ两者的选择都让我花费了好长的时间。从各种网站进行搜索两者的区别,一个又一个参数收入眼中,但还是没有什么概念。也许 技术选型 也是需要功力的。
但是慢慢地觉得,为何纠结呢,即使再有区别,在小项目的面前,并不会有什么体现的。
最重要的是关于两者的实现以及内核,才是我需要思考的。
时间线
2020.09.12-2020.09.13—完成初稿
参考链接
文档
RabbitMQ文档
https://www.rabbitmq.com/
RabbitMQ中文文档
http://rabbitmq.mr-ping.com/
http://rabbitmq.mr-ping.com/AMQP/AMQP_0-9-1_Model_Explained.html
RabbitMQ学习
https://www.cnblogs.com/wutianqi/p/10043011.html
关于RabbitMQ的问题的解决方案
-
消息丢失的解决方案
-
消息重复消费的重复方案
-
RabbitMQ常见面试题+评论
定义:AMQP与RabbitMQ
学习RabbitMQ一直都有AMQP的身影,之前以为AMQP只是实现RabbitMQ的一种协议。学习之后才知道,原来两者的关系是同等的,有联系但并不是谁依赖谁。脱离开对方,还有其它的用途与实现方式。
当我们使用RabbitMQ时,其实是在使用AMQP协议,RabbitMQ只是其中的一部分。
AMQP
AMQP即(Advanced Message Queue Protocol 高级消息队列协议):是一种网络协议,它支持符合条件的客户端和消息代理中间件进行通讯。
RabbitMQ
RabbitMQ是一个轻量级的消息代理中间件,支持多种协议,其中最为重要的是AMQP。
AMQP的概念同样符合RabbitMQ
AMQP和RabbitMQ
从上面就可以知道,其实AMQP和RabbitMQ有联系但并不是谁依赖谁。
AMQP支持各种信息交换的体系结构
存储转发,分布式事务,发布订阅,基于内容的路由,文件传输队列,点对点连接
其中发布订阅的一种实现就是RabbitMQ
RabbitMQ支持多种协议
官方文档描述:https://www.rabbitmq.com/protocols.html
AMQP 0-9-1和扩展协议, STOMP,MQTT,AMQP1.0,HTTP
但是RabbitMQ是通过插件机制支持AMQP之外的协议
特点
异步消息技术(支持多种消息协议,消息投递确认机制,多种交换器,灵活的消息路由)
支持多客户端语言
分布式集群部署
支持运行于多种操作系统
内置强大的服务器监控系统
AMQP
AMQP模型
组件
生产者(发送)
生产者顾名思义,就是生产消息的角色,生产者会将消息发送给交换机。
为了使交换机将正确地将消息发送给对队列,发送消息时需指定消息地路由键(routing key);
消息代理Broker(接收+发送)
Broker消息代理,这里指的是就是RabbitMQ,负责接收发布者发布的消息,并将消息推送给订阅了消息的消费者。
虚拟机Virtual Host
当多用户使用同一个RabbitMQ Server时,可以划分出多个vhost,并被用户使用。类似于一台计算机,有多用户。
交换机Exchange
交换机拿到一个消息之后,将它路由给一个或零个队列。使用哪种路由算法时有交换机类型和bingings的规则,即路由键所决定的。
路由键routing key
交换机与队列之间的绑定规则。
绑定Binding
交换机和队列之间通过路由键routing key 相互绑定起来。
消息队列Message Queue
消息的载体,消息将在这里等待消费者取走或推送给消费者。
Connection
生产者和消费者与消息代理之间的连接
通道Channel
每一次在消息代理与消费者之间建立连接的话,将会有巨大开销。
而Channel是Connection内部建立的逻辑连接,且相互隔离的,可以极大减少操作系统建立TCP Connection的开销。
消费者
接收消息的角色就是消费者
分析
正常情况下
生产者(publisher)生产具有指定路由键的信息将其发送到**消息代理Broker(RabbitMQ Server)中的交换机(Exchange);
交换机将收到的消息根据路由规则分发给绑定的队列(Message Queue);
最后Broker会通过连接中的通道(Channel)投递订阅了消息的消费者。
异常
从安全角度考虑,网络是不可靠的,所以处理消息的过程中会出现异常。
消息确认
基于此原因,AMQP模块包含了一个消息确认的概念
当一个消息从队列中投递给消费者后,消费者会通知以下消息代理。
这个机制可以是自动的,也可以是手动的(由开发者进行处理)。
当消息确认被启用时,消息代理不会完全将消息从队列中删除,直到收到来自消费者的确认回执。
与笔记“消息队列”中描述的邮局模型一致。
死信队列
在某些情况下,当一个消息无法被成功路由时,消息或许会被返回给发布者并被丢失。
或者,消息代理执行了延期操作,消息会被放入死信队列。
消息发布者可以选择某些参数来处理这些特殊情况。
处理机
处理机类型
处理器类型主要有4种——直连交换机,扇形交换机,主题交换机,头交换机,还有1种默认交换机。
默认交换机default exchange
实际上是由消息代理预先声明好的直连交换机
每个新建队列都会自动绑定到默认的交换机上,绑定的路由键名称与队列名称相同。如下:
换句话说,默认交换机看起来貌似能够直接将消息投递给队列,尽管技术上并没有做相关的操作。
直连交换机direct exchange
根据消息携带的路由键将消息投递给对应队列。直连交换机用来处理消息的单播路由(也可以处理多播路由);
所以直连交换机更像是一对一交换机.
工作流程
将一个队列绑定到某个交换机上,同时赋予该绑定一个路由键.
当一个携带路由键为R的消息被发送到直连交换机时,交换机会把它路由给routing key为R的队列.
注意:直连交换经常通过循环分发的方式发送消息,所以消息的负载均衡是发生在消费者之间,而不是队列之间.
扇形交换机fanout exchange
扇形交换机会将消息路由到所有与之绑定的队列,而不理会路由键,所以扇形交换机,也称为广播交换机.
应用案例
- 大规模多用户在线游戏使用它来处理排行榜更新等全局事件,注意是实时
- 体育新闻网站使用它近乎实时将比分更新分发给移动客户端
- 广播各种状态和配置更新
主题交换机
主题交换机通常用户实现消息的多播路由,只要消息的路由键符合交换机与队列之间的路由键模式,就会将消息路由到该队列.
其中主题是有路由键的模式决定的.
规则
其实这些规则有点像是正则表达式的镜像,有以下几点:
- 使用.分隔单词
- 一个单词使用*
- 0个或多个单词使用#
根据以上规则,有以下例子:
*.zhj.*
# 可以匹配以下内容
pro.zhj.check check.zhj.image # 使用*表示1个字符
#.zhj.*
# 可以匹配以下内容
zhj.pro.check # 使用#表示0个字符
zhj.check.zhj.image # 使用#表示多个字符
应用案例
其实 主题就代表分类,所以分类新闻之类的模块都是使用主题交换机.
头交换机(header exchange)
头交换机的头指的是消息头。头交换机会使用多个匹配的header与队列绑定.消息从生产者处发送到交换机时,会将消息的消息头与交换机与队列绑定的消息头进行匹配,符合的话,就会将该条消息发送给符合的队列.
规则
消息头可以是整数,也可以是一个字典.当消息头是一个字典时:
message_header = {
'x-match':any,
...
}
# 以上消息头 只要message_header中的一条属性值匹配,即符合
message_header = {
'x-match':all,
...
}
# 以上消息头 必须message_header中的所有属性值匹配,才符合
总结
AMQP0-9协议一共有4种交换机类型,另外还有一种默认交换机。
直连交换机,扇形交换机,主题交换机,头交换机
前三种是根据路由键routing key与队列相互绑定的,而最后一种头交换机是通过消息头绑定的。
交换机的职责非常简单,就是根据绑定的规则,将消息发送到队列中。
处理机属性
名字Name
交换机名称。
持久性Durability
交换机有持久(durable)和暂存(transient)两个状态。
区别在于消息代理重启后,交换机是否存在。
持久表示消息代理重启后,交换机还是存在的。而暂存则相反,需要消息代理上线后重新定义。
自动删除Auto-delete
当所有与之绑定的消息队列都完成了对此交换机的使用后,删掉它。
Arguments依赖代理本身
队列
AMQP中的队列和其它消息队列一样,存储着即将被应用消费的消息。
属性
Name
Durable
同交换机一样的概念,消息代理重启后,队列是否存在
Exclusive
只被一个连接使用,当连接关闭后,队列即将被删除
Auto-delete
当最后一个消费者退订后即被删除
Arguments
名称
队列的名称可以由应用来取,也可以让消息代理自动生成。
持久化
持久化队列会被存储在磁盘上,当消息代理重启时,依旧存在;暂存队列则相反。
另外,持久化队列的持久性只是对于队列而言,所以持久化队列处理的消息如果没有持久化的话,
该消息也是不能重新恢复的。
绑定
绑定是一个名词,指的是交换机与队列之间的绑定。
常常绑定会与路由键一起出现,因为消息是根据路由键路由到某个队列的。
生产者
生产者是指消息的生产者。消息从生产者生成后,发送给消息代理,即RabbitMQ。
动作:推送消息
动作:消息确认
生产者推送消息到Rabbit Server的消息确认有4种情况,分别是:
- 找不到交换机
- 找到了交换机,但是找不到队列
- 交换机和队列都找不到
- 推送成功
总结:其实就是2个对象交换机和队列,2种状态找到与找不到两两组合。
消费者
消息的意义在于被应用消费。而消费者就是实现者。
动作:推和拉
为了达到此目的,有两种方式:
- 队列将消息投递给应用
- 应用根据需要主动获取消息
从上面的两种方式,可以有以下画面:
区别
-
动作的发起者不同
动作推的发起者是队列,队列将消息推给消费者;
动作拉的发起者是消费者,消费者从队列拉取消息
网络是不可靠的,因为不知道处理消息的过程中会发生什么?网络中断,服务宕机都有可能会发生。
所以需要一些动作来确保消息能够被正常处理。
动作:消息确认
消息的确认影响着AMQP的消息代理什么时候删除消息。有2种解决方案。
-
自动确认模式:当消息代理将消息发送给应用后立即删除消息
-
手动确认模式:待应用发送一个确认回执后删除消息
注意:手动确认模式中应用发送确认回执并不是说收到消息后,而是由应用自己决定。
即应用可以在收到消息后立即发送,或者将未处理的消息存储后发送,亦或者等到消息被处理完毕后再发送,共3种情况下发送确认回执。
这里涉及2个动作——消息代理删除消息,消费者发送确认回执。
当然,这些的前提是消费者没有挂掉。
当消费者挂掉之后,即消息代理与消费者的连接中断,消息代理会知道这一状况,
并会把消息重新发送给另一个符合要求的消费者。
如果没有符合的消费者,消息代理会死等下一个符合要求的消费者,再进行发送。
这一切,源于消息代理的一个机制——当开启确认回执功能后,消息代理尚未得到确认回执,消息代理会重新发送一遍。
动作:拒绝消息
如果拒绝消息,消费者应该向消息代理表明——本条消息由于“拒绝消息”的原因处理失败。
并且告诉消息代理如何处理该条消息——销毁或者重新放入队列。
如果当前只有一个符合但不适合的消费者,不可选择重新放入队列,因为会造成死循环。
消息代理发过去,消费者收到但不想/不适合处理,又发回给消息代理。无限死循环。
消息
其实说了那么多,有一个非常重要的对象也是需要说一说的——消息
消息由生产者生成,发送到交换机,交换机再将其路由到某个队列。
队列再将其发送给消费者。可以说消息串联起了整个工作流程。
属性
内容类型Content type
内容编码Content encoding
路由键Routing key
投递模式Delivery mode
即前面所说的持久还是暂存
消息能够以持久化的方式发布,其持久化在磁盘上。
消息的持久性完全取决于自身,处理机和队列的持久性不会影响消息的持久性。
消息优先权Message priority
消息发布的时间戳Message publishing timestamp
消息有效期Expiration period
发布者ID—Publisher application id
消息头headers
消息属性需要在消息被发布的时候定义。
消息确认
AMQP模型有两个消息确认,分别是生产者推送消息确认,以及消费者接收消息后的消息确认
思维导图
总结
以上便是全部内容,当然还有许多概念没有讲述完整。等学习到了再进行补充。