RabbitMQ消息可靠性分析和应用
RabbitMQ流程简介(带Exchange)
RabbitMQ使用一些机制来保证可靠性,如持久化、消费确认及发布确认等。
先看以下这个图:

P为生产者,X为中转站(Exchange),红色部分为消息队列,C1、C2为消费者。
整个流程分成三部分:第一,生产者生产消息,发送到中转站;第二,中转站按定义的规则转发消息到消息队列;第三,消费者从消息队列获取消息进行消费(处理)。
RabbitMQ消息可靠性分析和应用
应用代码均使用C#客户端代码实现。
一、发布确认
生产者生产消息,发送到中转站的过程中,可能会因为网络丢包、网络故障等问题造成消息丢失。为了确保生产者发送的消息不会丢失,RabbitMQ提供了发布确认(Publisher Confirms)机制,从而提高消息的可靠性(注意:发布确认机制不能和事务机制一起使用)。
单条消息发布确认:
channel.ConfirmSelect();//发布确认机制
string message = "msg";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(
exchange: "MarkTopicChange",
routingKey: "MarkRouteKey.one",
basicProperties: null,
body: body
);
bool isPublished = channel.WaitForConfirms();//通道(channel)里消息发送成功返回true
使用channel.ConfirmSelect,一旦信道进入确认模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始)。消息被投递到所有匹配的队列之后,RabbitMQ就会发送(Basic.Ack)给生产者(包含消息的唯一ID),生产者从而知道消息发送成功。
多条消息发布确认:
channel.ConfirmSelect();//发布确认机制
foreach (var itemMsg in lstMsg)
{
byte[] sendBytes = Encoding.UTF8.GetBytes(itemMsg);
//发布消息
channel.BasicPublish(
exchange: "MarkTopicChange",
routingKey: "MarkRouteKey.one",
basicProperties: null,
body: sendBytes
);
}
bool isAllPublished = channel.WaitForConfirms();//通道(channel)里所有消息均发送才返回true
注意:多消息发布确认机制情况下,倘若要发送100条消息,发送90条后,突然网络故障,后面的消息发送失败了,那么isAllPublished返回的是false,而前面90条消息已经发送到消息队列了。我们还不知道哪些消息是发送失败的,所以很多条消息发布确认,建议分几次发送或多通道发送。
此外,需要确保在中转站(Exchange)的消息可以顺利到达消息队列。
(1)首先需要定义匹配的Exchange和Queue,根据Exchange的类型和routingKey确定转发的关系。
(2)确保消息队列有足够内存存储消息。
RabbitMQ默认配置vm_memory_high_watermark为0.4。意思是控制消息占40%内存左右。vm_memory_high_watermark_paging_ratio为0.5,当消息占用内存超过50%,RabbitMQ会把消息转移到磁盘上以释放内存。当磁盘剩余空间小于阀值disk_free_limit(默认为50M),所有生产者阻塞,避免充满磁盘,导致所有的写操作失败。
RabbitMQ配置文件一般在%APPDATA%\RabbitMQ\rabbitmq.config.
%APPDATA% 一般为 C:\Users\%USERNAME%\AppData\Roaming(Windows环境)
二、持久化
消息存放到消息队列后,在不配置消息持久化的情况下,若服务器重启、关闭或宕机等,消息都会丢失。配置持久化可以有效提高消息的可靠性。持久化需要同时配置消息持久化和队列持久化。单配置消息持久化,队列消失了,消息没有地方存放;单配置队列持久化,队列还在,消息没了。
队列持久化在定义队列时候配置
//定义队列
channel.QueueDeclare(
queue: "Mark_Queue", //队列名称
durable: true, //队列磁盘持久化
exclusive: false,//是否排他的,false。如果一个队列声明为排他队列,该队列首次声明它的连接可见,并在连接断开时自动删除
autoDelete: false,//是否自动删除,一般设成false
arguments: null
);
消息持久化在发布消息时候配置
//消息持久化,把DeliveryMode设成2
IBasicProperties properties = channel.CreateBasicProperties();
properties.DeliveryMode = ;
//发布消息
channel.BasicPublish(
exchange: "MarkTopicChange",
routingKey: "MarkRouteKey.one",
basicProperties: properties,
body: sendBytes
);
如何配置了事务机制或发布确认(publisher confirm)机制,服务端的返回Basic.Ack是在消息落盘之后执行的,进一步的提高了消息的可靠性。
为了防止磁盘损坏带来的消息丢失,可以配置镜像队列,这里不作介绍。
三、消费确认
为了确保消息被消费者消费,RabbitMQ提供消费确认模式(consumer Acknowledgements)。自动确认模式,当消费者成功接收到消息后,自动通知RabbitMQ,把消息队列中相应消息删除。这很大程度上满足不了我们,假如消费者接收到消息后,服务器宕机,消息还没处理完成,这样就会造成消息丢失。手动确认模式,当消费者成功处理完消息后,手动发消息通知RabbitMQ,把消息队列中相应消息删除。
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
var routingKey = ea.RoutingKey;
Console.WriteLine(" [x] Received '{0}':'{1}'",
routingKey,
message); //确认该消息已被消费,发删除消息给RabbitMQ,把消息队列中的消息删除
channel.BasicAck(ea.DeliveryTag, false);
//消费消息失败,拒绝此消息,重回队列,让它可以继续发送到其他消费者
//channel.BasicReject(ea.DeliveryTag, true);
//消费消息失败,拒绝多条消息,重回队列,让它们可以继续发送到其他消费者
//channel.BasicNack(ea.DeliveryTag, true, true);
};
//手动确认消息,把autoAck设成false
channel.BasicConsume(queue: "Mark_Queue",
autoAck: false,
consumer: consumer);
这里值得注意的是,消息处理完成后,一定要把处理完成的消息发送到RabbitMQ(channel.BasicAck(ea.DeliveryTag, false)),不然RabbitMQ会一直等待,从而造成内存泄露。若处理消息过程中发生异常,可以使用channel.BasicReject(ea.DeliveryTag, true)来拒绝此消息,让它重回队列。若RabbitMQ收不到消费者任何确认消息的信号(包括确认信号,拒绝信号灯),直到此消费者断开连接,消息才能重回队列,继续发送到其他消费者。
提醒一下,假如消费者消费消息的方法不支持并发(取决于需求),可以限制消费者每次只接收一条消息。
channel.BasicQos(, , false);
RabbitMQ消息可靠性分析和应用的更多相关文章
- RabbitMQ消息可靠性分析
消息中间件的可靠性是指对消息不丢失的保障程度:而消息中间件的可用性是指无故障运行的时间百分比,通常用几个 9 来衡量.不存在绝对的可靠性只能尽量趋向完美.并且通常可靠性也意味着影响性能和付出更大的成本 ...
- RabbitMQ消息可靠性分析 - 简书
原文:RabbitMQ消息可靠性分析 - 简书 有很多人问过我这么一类问题:RabbitMQ如何确保消息可靠?很多时候,笔者的回答都是:说来话长的事情何来长话短说.的确,要确保消息可靠不只是单单几句就 ...
- [转载]RabbitMQ消息可靠性分析
有很多人问过我这么一类问题:RabbitMQ如何确保消息可靠?很多时候,笔者的回答都是:说来话长的事情何来长话短说.的确,要确保消息可靠不只是单单几句就能够叙述明白的,包括Kafka也是如此.可靠并不 ...
- RabbitMQ消息可靠性传输
消息的可靠性投递是使用消息中间件不可避免的问题,不管是使用kafka.rocketMQ或者rabbitMQ,那么在RabbitMQ中如何保证消息的可靠性投递呢? 先再看一下RabbitMQ消息传递的流 ...
- RabbitMQ消息可靠性、死信交换机、消息堆积问题
目录 消息可靠性 生产者消息确认 示例 消费者消息确认 示例 死信交换机 例子 高可用问题 消息堆积问题 惰性队列 参考 消息可靠性 确保消息至少被消费了一次(不丢失) 消息丢失的几种情况: 消息在网 ...
- RabbitMQ消息可靠性
那些情况会失败 网络问题有很多原因出发失败.防火墙也可能会中断Idle连接,网络失败不是很快确定的. 硬件和软件也会导致系统崩溃.客户端软件保持运行,而逻辑错误也可能会导致channel和connec ...
- 消息中间件-RabbitMQ消息可靠性和插件化机制
package com.study.rabbitmq.a132.confirm; import com.rabbitmq.client.*; import java.io.IOException; i ...
- 解决RabbitMQ消息丢失问题和保证消息可靠性(一)
原文链接(作者一个人):https://juejin.im/post/5d468591f265da03b810427e 工作中经常用到消息中间件来解决系统间的解耦问题或者高并发消峰问题,但是消息的可靠 ...
- SpringCloud之RabbitMQ消息队列原理及配置
本篇章讲解RabbitMQ的用途.原理以及配置,RabbitMQ的安装请查看SpringCloud之RabbitMQ安装 一.MQ用途 1.同步变异步消息 场景:用户下单完成后,发送邮件和短信通知. ...
随机推荐
- 关于apache 开启 ssl https 支持 TLS1.2 的些事
项目背景 需要搭建一个小程序的服务器,当然要使用https协议服务器windows service 2012 r2,后台语言是php,服务集成环境装的是appserv2.5 ,apache2.2证书申 ...
- android彻底关闭应用程序方法
Android SDK > 7(Android2.1)之后,即Android2.2及以后版本彻底关闭应用的方法,目前试验只有一下方法有效: Intent startMain = new Inte ...
- 教你如何使用android studio发布release 版本【转】
原文链接 想必还有人对如何在Android studio (以下简称as)发布release版本的app而狂刷百度吧?都是过来人,我很理解这种心情,百度到的基本是半成品,为什么这么说呢?百度一下,你就 ...
- atof()函数 atol()
atof()函数 atof():double atof(const char *str ); 功 能: 把字符串转换成浮点数 str:要转换的字符串. 返回值:每个函数返回 double 值,此值由将 ...
- Linux下svn常用指令【转】
转自:http://blog.csdn.net/myarrow/article/details/8110858 Windows下的TortoiseSVN是资源管理器的一个插件,以覆盖图标表示文件状态, ...
- java多线程系列六、线程池
一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池. 2. 使用线程池的好处 a) 降低资源的消耗.使用线程池不用频繁的创建线程和销毁线程 b) 提高响应速度,任 ...
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)
传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...
- javaScript中自定义sort中的比较函数,用于比较字符串长度,数值大小
, 1.2, 'bb', 'cc']; var len = arr.length; // for (var i = 0; i < len; i++) { // alert(arr + &qu ...
- 卓越的目标检测器Pelee
Densenet的改良—PeleeNET Pelee: A Real-Time Object Detection System on Mobile Devices 论文地址:https://arxiv ...
- 用Kotlin破解Android版微信小游戏-跳一跳
前言 微信又更新了,从更新日志上来看,似乎只是一次不痛不痒的小更新.不过,很快就有人发现,原来微信这次搞了个大动作——在小程序里加入了小游戏.今天也是朋友圈被刷爆的缘故. 看到网上 有人弄了一个破解版 ...