RabbitMQ消息模型概览(简明教程)
小菜最近用到RabbitMQ,由于之前了解过其他消息中间件,算是有些基础,所以随手从网上搜了几篇文章,准备大概了解下RabbitMQ的消息模型,没想到网上文章千篇一律,写一大堆内容,就是说不明白到底怎么回事,真是逼小菜写博客…
首先说明本文只适合有消息中间件基础的读者,本文不会讲解基础概念,而是一针见血的指明RabbitMQ该怎么用,告诉读者RabbitMQ能做什么,而不是像网络上其他文章那样花里胡哨抓不住重点。
好了,直入正题。
simple简单队列
这种队列,纯属RabbitMQ搞的一个花样,仅仅是个概念而已!并不是实际的队列类型!他就是在假设某个队列只有一个消费者,也就是说,读者在实际使用中,某个队列傻傻的只用一个消费者去消费,这就叫simple简单队列啦,应用场景极少,一般情况下消费端都会有多个消费者。
Fair dispatch公平分发
这种队列让人一看,有点蒙逼,实际上这个概念非常非常简单,如果读者用过redis的话,这个队列模式很像redis的list用法,只不过redis是拉取模型,而mq是推送模型。
这个公平,可不是说消息平均的发送给消费者,恰恰相反,消费者消费消息的多少,完全取决于消费者的处理能力,能者多劳,相当于消费者主动从mq中取消息,而不是被mq安排消息。
实现上也不难理解,消费端消费数据时,会有一个确认消费完成的动作,mq收到消费完成的通知后,才会继续向该消费者发送消息,因此,如果消费者处理速度快,那么最终mq向它发送的消息就多,如果消费者处理的慢,mq向它发送的消息就少。
在这小菜贴出java代码实现的关键点:

当然,这是消费端代码,仅仅在消费端做处理即可,对于生产端来说是透明的,不需要做任何处理。
Round-robin轮询分发
所谓轮询分发,就是公平分发的退化版,打开自动通知,去掉手动通知,去掉消费端消费条数限制,就是轮询分发啦!!!
其实轮询分发就是利用了自动通知参数,开启了自动通知,mq根据一个简单的规则(比如取模运算),先确定好哪些消息发送给哪些消费者,无论消费者处理能力如何,这些消息都得让你处理,因此每个消费者最终处理的消息数量,是相同的(忽略"消息数量/消费者"不能整除的情况)。
这种模式很明显是有问题的,首先,这种模式不能很好的利用消费端的性能差异,做不到真正意义上的负载均衡,浪费资源;其次(只是猜测),这种模型还有可能造成大量消息堆积在消费者容器中,这是非常危险的,不仅会造成消息丢失,还有可能压垮消费者。
publish_subscribe发布订阅模式
RabbitMQ 中有一个交换机Exchanges的概念,发布订阅就是通过交换机实现的。
交换机的概念非常简单,就是一个转发器,有了交换机之后,生产端先把消息发送到交换机,然后交换机再把消息发送到与其绑定的消息队列,这样就解决了生成端如何把一条消息批量发送到多个消息队列的问题。
交换机本身没有数据存储能力,仅仅是一个代理,可以理解成nginx。
因此,实现发布订阅的关键在于:
· 生产端(发布端)直接发送消息到交换机,而不是具体的消息队列。
· 多个消费端(订阅端)将自己的消息队列绑定到同一个交换机上。
这样就实现了发布订阅。
routing路由模式
路由模式仅仅基于发布订阅搞了一点小事情,在发布订阅模式中,交换机无脑向所有与之绑定的消息队列发送消息,而路由模式对交换机做了一些限制,它指定了一个route key,生产端向交换机发送消息时,指定消息的route key,消费端将消息队列绑定到交换机时,也指定该队列消费的route key,这样一来,交换机就可以根据消息的route key,将该消息转发到绑定(消费)该route key的消息队列。
生产端关键点:

消费端关键点:

topic主题模式
RabbitMQ又开始搞花样了,咋一看topic小菜还以为是kafka里的topic概念呢,弄的莫名其妙。
主题模式其实就是路由模式的一个加强,而且是非常非常非常简单的一个加强:route key支持通配符。
主题模式和路由模式完全一样,只不过是消费端route key不用写死,增加了一个模糊匹配的功能,这样在某些场景下,消费端就不用逐一绑定所有监听的route key,直接用抽象的通配符表示即可,当然,这是针对消费端的优化,与生产端无关。
关于RabbitMQ的可靠性
消费端的消费可靠性,已经在"Fair dispatch公平分发"章节中做了介绍,即利用手动通知告诉mq消费成功,但通知也有不可达的可能,进而涉及到重发,具体的处理细节,读者自行查阅资料。
生产端的提交可靠性,可以通过mq的回调机制实现,即生产端发送消息时自己维护一份已发送消息的集合,mq收到某条消息之后,会向生产端发送一个接收成功确认(体现在代码中就是回调),然后生产端根据确认消息的唯一id,从自己维护的已发送消息集合中移除该消息,从而确保每条消息都成功发送到了mq。
假如某些消息未成功到达mq,那么就不会有对应消息的确认,最终集合中会有剩余元素(理想情况下是没有的),这些剩余元素,就是发送失败的消息,需要重发。
简单展示下代码关键点( 生产端):

虽然确认机制可以保证消息的可靠性,但是必然带来性能损失,因此到底需不需要开启生产端或消费端的确认机制,需要根据业务场景具体分析。
一些注意事项
RabbitMQ的Connection是昂贵的,但Channel是廉价的,在多线程环境下,尽量创建少数Connection,然后在每个Connection中创建多个Channel,利用Channel实现Connection复用,从而提高系统性能。很像Java NIO里的Selector到Channel的多路复用。
生产端发送消息时,同一个Channel的basicPublish方法并不是线程安全的,因此更加体现出多Channel的重要性。如果生产端需要使用多线程发送消息,那么必须创建多个Channel,每一个线程单独使用一个Channel,但是这些Channel可以来自同一个Connection。假如线程数量过多,那么也不可以无限制的创建Channel,需要使用Channel Pool(连接池)的思路去控制并发。
对于同一个Channel而言,发送消息和接受消息是互不影响的,可以进行并发操作。
吐槽
最后吐槽一下RabbitMQ客户端API设计的真难用,同一个API竟然通过参数值重载,就比如向消息队列发送消息是这样:
channel.basicPublish("","队列名称", null, message.getBytes());
然后向交换机发消息是这样:
channel.basicPublish("交换机名称","route key", null, message.getBytes());
同一个方法,第二个参数的含义,竟然是通过第一个参数是否为空决定的,厉害了~
RabbitMQ消息模型概览(简明教程)的更多相关文章
- RabbitMQ之五种消息模型
首先什么是MQ MQ全称是Message Queue,即消息对列!消息队列是典型的:生产者.消费者模型.生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息.因为消息的生产和消费都是异步的,而 ...
- RabbitMQ消息的交换
消息的交换 目录 RabbitMQ-从基础到实战(1)— Hello RabbitMQ RabbitMQ-从基础到实战(2)— 防止消息丢失 1.简介 在前面的例子中,每个消息都只对应一个消费者,即使 ...
- Rabbitmq消息队列(四) 发布订阅
1.简介 在上篇教程中,我们搭建了一个工作队列,每个任务只分发给一个工作者,在本篇教程中,我们要做的跟之前完全不一样 —— 分发一个消息给多个消费者(consumers).这种模式被称为“发布/订阅” ...
- ArcGIS Pro 简明教程(4)工具和模型构建器
ArcGIS Pro 简明教程(4)工具和模型构建器 by 李远祥 工具箱中的工具 ArcGIS Pro 在1.3版本基本上已经继承了ArcMap的所有工具,而且会不断加入一些它自身才有的工具,例如适 ...
- rabbitmq五种消息模型整理
目录 0. 配置项目 1. 基本消息模型 1.1 生产者发送消息 1.2 消费者获取消息(自动ACK) 1.3 消息确认机制(ACK) 1.4 消费者获取消息(手动ACK) 1.5 自动ACK存在的问 ...
- 2013 duilib入门简明教程 -- 事件处理和消息响应 (17)
界面的显示方面就都讲完啦,下面来介绍下控件的响应. 前面的教程只讲了按钮和Tab的响应,即在Notify函数里处理.其实duilib还提供了另外一种响应的方法,即消息映射DUI_BEG ...
- duilib教程之duilib入门简明教程17.事件处理和消息响应
界面的显示方面就都讲完啦,下面来介绍下控件的响应. 前面的教程只讲了按钮和Tab的响应,即在Notify函数里处理.其实duilib还提供了另外一种响应的方法,即消息映射DUI_BEGIN_ME ...
- RabbitMQ,RocketMQ,Kafka 消息模型对比分析
消息模型 消息队列的演进 消息队列模型 发布订阅模型 RabbitMQ的消息模型 交换器的类型 direct topic fanout headers Kafka的消息模型 RocketMQ的消息模型 ...
- RabbitMQ消息队列系列教程(二)Windows下安装和部署RabbitMQ
摘要 本篇经验将和大家介绍Windows下安装和部署RabbitMQ消息队列服务器,希望对大家的工作和学习有所帮助! 目录 一.Erlang语言环境的搭建 二.RabbitMQ服务环境的搭建 三.Ra ...
随机推荐
- openlayers4 入门开发系列之风场图篇
前言 openlayers4 官网的 api 文档介绍地址 openlayers4 api,里面详细的介绍 openlayers4 各个类的介绍,还有就是在线例子:openlayers4 官网在线例子 ...
- Linux记录~持续更新~
ls -ildha /etc -i 显示对应id号 唯一标识 -l 显示详情 -d 显示当前文件夹 不包括子目录 -h 单位为KB 而不是B -a 显示所有 包括隐藏文件 mkdir mkdir -p ...
- postgresql 使用pg_restore时显示role "root" does not exist的解决办法
在docker里恢复bakcup格式的数据库,结果提示role "root" does not exist 解决方法: 切换用户: su - postgres 然后再次运行命令: ...
- 解决Ajax请求时无法重定向的问题
今天发现,当使用Ajax请求时,如果后台进行重定向到其他页面时是无法成功的,只能在浏览器地址栏输入才能够实现重定向. Ajax默认就是不支持重定向的,它是局部刷新,不重新加载页面. 需要实现的功能是, ...
- Packets larger than max_allowed_packet are not allowed(mysql数据查询提示:不允许超过允许的最大数据包)解决方案
问题背景: 首先我的项目运用的时Mysql,在做一个数据更新操作的时候,提示异常:System.Exception:“ExecuteNonQuery:Packets larger than max_a ...
- python实现列表的排序
群里有同行遇到这样一个面试题:有一个整数构成的列表,需要给这个列表进行从小到大存入到另一个列表中. 本身排序可以用python的内置函数sort和sorted,但题目的要求是手动实现. 看起来很简单, ...
- Python 进度条显示
运行工具:Pycharm, import timescale = 50print("开始执行".center(scale//2,"-")) start = ti ...
- 使用 coverlet 查看.NET Core应用的测试覆盖率
代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率. Visual Studio 2017的企业版可以直接查看测试的代码覆盖率, ...
- Sql Server 的参数化查询
为什么要使用参数化查询呢?参数化查询写起来看起来都麻烦,还不如用拼接sql语句来的方便快捷.当然,拼接sql语句执行查询虽然看起来方便简洁,其实不然.远没有参数化查询来的安全和快捷. 今天刚好了解了一 ...
- 我的2018OKR年终回顾与2019OKR初步规划
转眼一年又过去了,在这个年底的时候,按照国际惯例,又到了重新回顾审视一下这一年来的得失,规划一下明年的奋斗方向的时候了.因此,我继续使用OKR来给自己做Review和Planning,也希望自己能够保 ...