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 ...
随机推荐
- Web学习的第四天
今天通过前面的学习,自己写了段代码. 今天还学习了列表,列表的分类有:无序列表.菜单列表.目录列表.有序列表.定义列表. 列表类型 标记符号 ...
- Python之路【第四篇】:Python基础之函数
函数的理解 面向过程:根据业务逻辑从上到下垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 函数作用是你的程序有良好的扩展性.复用性. 同样的功能要是用3次以上的话就建议使 ...
- Vue(day6)
一.webpack中常用的文件loader & 插件 由于版本存在变动,以下安装和配置都有可能发生变化,请以官方文档为准. 1.html-webpack-plugin插件 html-webpa ...
- python maximum recursion depth exceeded 处理办法
1.在执行命令 pyinstaller -F D:\py\programe\banksystem.py打包生成.exe文件时报错:python maximum recursion depth exce ...
- 接口自动化:HttpClient + TestNG + Java(三) - 初步封装和testng断言
在上一篇中,我们写了第一个get请求的测试类,这一篇我们来对他进行初步优化和封装 3.1 分离请求发送类 首先想到的问题是,以后我们的接口自动化测试框架会大量用到发送http请求的功能. 那么这一部分 ...
- Cortex-M 实现互斥操作的三种方法
注:本文仅针对Cortex-M3/4 系列进行讲述. 在传统的ARM处理器架构中,常使用SWP指令来实现锁的读/写原子操作,但从ARM v6开始,读/写访问在独立的两条总线上进行,SWP指令已无法在此 ...
- SLAM+语音机器人DIY系列:(三)感知与大脑——1.ydlidar-x4激光雷达
摘要 在我的想象中机器人首先应该能自由的走来走去,然后应该能流利的与主人对话.朝着这个理想,我准备设计一个能自由行走,并且可以与人语音对话的机器人.实现的关键是让机器人能通过传感器感知周围环境,并通过 ...
- 文件输入输出流工具: IOUtils使用总结
序言 以前写文件的复制很麻烦,需要各种输入流,然后读取line,输出到输出流...其实apache.commons.io里面提供了输入流输出流的常用工具方法,非常方便.下面就结合源码,看看IOUTil ...
- InnoSetup 脚本打包及管理员权限设置
InnoSetup使用教程:InnoSetup打包安装 脚本详细 1. 定义变量 #define MyAppName "TranslationTool" #define MyApp ...
- windows共享文件夹
net share 查看本地共享文件夹 我们想要删除这些链接,删除所有的共享目录链接命令是: net use * /d 如果只是想删除单个共享目录的链接,那么命令是: net use \\主机名或IP ...