RabbitMQ(三):消息持久化策略
一、前言
在正常的服务器运行过程中,时常会面临服务器宕机重启的情况,那么我们的消息此时会如何呢?很不幸的事情就是,我们的消息可能会消失,这肯定不是我们希望见到的结果。所以我们希望AMQP服务器崩溃了也可以将消息恢复,这称之为消息持久化。RabbitMQ自然存在这种策略可以帮助我们完成这件事情。
二、持久化的消息
当RabbitMQ服务器重启后,原先的队列和交换器会随同里面的消息一同消失。原因在于每个队列和交换器都有durable属性,该属性默认是false,它决定了RabbitMQ是否需要在崩溃或者重启之后重新创建队列或者交换器。将它设置为true就代表了持久性,在服务器重启之后就会重新持久的创建队列和交换器。
当然做到这点还不够,我们需要的是持久化的消息,所以在消息发布前,通过将消息的“投递模式”(delivery mode)属性设置为2将消息标记为持久化。到目前为止,消息还只是被表示为持久化,还需要被发布到持久化的交换器中并到达持久化的队列中才行。如果不是这样,包含持久化消息的队列或者交换器挥着Rabbit崩溃重启后不复存在,导致消息成为一个孤儿。因此,总结起来需要做到以下三点:
(1)将消息的投递模式选项设置为2(持久);
(2)将消息发送到持久化的交换器;
(3)消息到达持久化的队列。
注意,如果原先有非持久的交换器或者队列,需要删除后才可重新创建,否则就创建其他名称的交换器或者队列,代码如下:
//声明持久交换器
channel.ExchangeDeclare(
"HelloExchange", //交换器名称
ExchangeType.Direct,//交换器类型
true, //是否持久话
false, //是否自动删除
null //关于交换器的详细设置,键值对形式
);
//声明持久队列
channel.QueueDeclare(
"HelloQueue",//队列名称
true, //是否持久化
false, //是否只对首次声明的队列可见
false, //是否自动删除
null ////关于队列和队列内消息的详细设置,键值对形式
);
//发布持久消息
string msg_str = "这是生产者第一次发布的消息";
IBasicProperties msg_pro = channel.CreateBasicProperties();
msg_pro.ContentType = "text/plain";//发布的数据类型
msg_pro.DeliveryMode = ;//标记持久化
三、事务
目前为止,我们已经将消息、队列和交换器设置为持久化。但是事实上还存在着'最后一英里'的距离,就是在把消息写入磁盘前,消息由于服务器宕机而消失该如何?这时候就需要使用到事务,说到事务就会想到SQL中的事务,但是不能搞混了。AMQP中,在把信道设置为事务模式后,通过信道发送消息后还有多个其他的AMQP命令,这些命令是执行还是忽略,取决于消息的发送是否成功,消息发送成功信道会在事务中完成其他AMQP命令,就可以提交事务了,发送失败则其他AMQP命令将不会执行,我们也会知道发送失败,而采取相应的措施。事务保证了解决这最后的问题。
代码如下:
using (IConnection conn = conn_factory.CreateConnection())
{
//2.创建信道
using (IModel channel = conn.CreateModel())
{
try
{
channel.TxSelect();//声明事务
//3.发布消息
string msg_str = "这是生产者发布的消息";
IBasicProperties msg_pro = channel.CreateBasicProperties();
msg_pro.ContentType = "text/plain";//发布的数据类型
msg_pro.DeliveryMode = ;
channel.BasicPublish(
"HelloExchange", //消息发送目标交换器名称
"hola", //路由键
msg_pro, //消息的发布属性
Encoding.UTF8.GetBytes(msg_str) //消息
);
channel.TxCommit();//提交事务
}
catch(Exception ex)
{
channel.TxRollback();//回滚事务
}
}
}
四、发送方确认模式
虽然通过事务和持久化的消息、队列和交换器可以确保消息不会丢失,但是对消息的吞吐量有着非常严重的影响,而且使用消息通信就是为了避免同步,可是事务却会导致生产者程序产生同步。所以,有一个更好的方法保证消息投递:发送方确认模式。和事务类似,我们需要将信道channel设置为confirm模式,而且只能通过重新创建信道来关闭该设置。一旦信道进入confirm模式,所有的信道上发布的消息都会被指派一个唯一的ID。当消息被投递到队列后,信道就会发送一个发送方确认模式给生产者程序,使得生产者知道消息安全到达队列了。
发送发确认模式最大的好处是它们是异步的,没有回滚的概念,更加轻量级,对性能的影响也几乎忽略不计。
代码如下:
channel.ConfirmSelect();//开启发送确认模式
//3.发布消息
IBasicProperties msg_pro = channel.CreateBasicProperties();
msg_pro.ContentType = "text/plain";//发布的数据类型
msg_pro.DeliveryMode = ;
for(int i = ; i < ; i++)
{
string msg_str = string.Format("这是生产者发布的消息{0}", i);
channel.BasicPublish(
"HelloExchange", //消息发送目标交换器名称
"hola", //路由键
msg_pro, //消息的发布属性
Encoding.UTF8.GetBytes(msg_str) //消息
);
if (channel.WaitForConfirms())
Console.WriteLine(i);
else
Console.WriteLine("发送失败");
}
可以看到channel.WaitForConfirms()方法是同步的,这样的话效率会低一点,我们可以发送完所有的消息,然后用channel.WaitForConfirmsOrDie()一次性提交,如果中途有一个消息提交失败或者超时,就会报错Exception,需要全部重新提交。
五、小结
消息持久化的策略大致就是以上几种,我们可以根据自己的实际需求来选择相应的策略。如果有问题欢迎指出!
RabbitMQ(三):消息持久化策略的更多相关文章
- RabbitMQ 的消息持久化与 Spring AMQP 的实现剖析
文章目录 1. 原生的实现方式 2. Spring AMQP 的实现方式 要从奔溃的 RabbitMQ 中恢复的消息,我们需要做消息持久化.如果消息要从 RabbitMQ 奔溃中恢复,那么必须满足 ...
- 【python】-- RabbitMQ 队列消息持久化、消息公平分发
RabbitMQ 队列消息持久化 假如消息队列test里面还有消息等待消费者(consumers)去接收,但是这个时候服务器端宕机了,这个时候消息是否还在? 1.队列消息非持久化 服务端(produc ...
- RabbitMQ的消息持久化处理
1.RabbitMQ的消息持久化处理,消息的可靠性是 RabbitMQ 的一大特色,那么 RabbitMQ 是如何保证消息可靠性的呢——消息持久化. 2.autoDelete属性的理解. 1).@Qu ...
- 快速掌握RabbitMQ(三)——消息确认、持久化、优先级的C#实现
1 消息确认 在一些场合,如转账.付费时每一条消息都必须保证成功的被处理.AMQP是金融级的消息队列协议,有很高的可靠性,这里介绍在使用RabbitMQ时怎么保证消息被成功处理的.消息确认可以分为两种 ...
- RabbitMQ原理与相关操作(三)消息持久化
现在聊一下RabbitMQ消息持久化: 问题及方案描述 1.当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间.在此过程中可能会出现一些意外,比如消息接收 ...
- RabbitMQ之消息持久化(转)
原文地址 https://blog.csdn.net/u013256816/article/details/60875666/ 消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证 ...
- RabbitMq初探——消息持久化
消息持久化 前言 通过上一节,我们知道,有消息确认机制,保证了当消费者进程挂掉后,消息的不丢失. 但是如果rabbitmq挂掉呢?它的队列和消息都会丢失的.为了保证消息在rabbitmq挂掉重启后不丢 ...
- RabbitMQ之消息持久化
消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢——消息持久化. 为了保证RabbitMQ在退出或者crash等异常情况下数据没有丢失,需要将queue,exch ...
- RabbitMQ之消息持久化(队列持久化、消息持久化)
rabbitMQ不支持数据库的持久化,只支持内存以及文件持久化 https://blog.csdn.net/bwh0520/article/details/78746873 http://blog.y ...
随机推荐
- 分享:Windows2008重启后提示系统恢复选项的解决办法
如题:WINdows2008服务器. 重启后提示系统恢复选项的解决办法 使用windows 2008后,不能启动的问题,重启后出现 修复系统选项 采用下面帖子中的部分命令搞定之. 我自己是直接使用:选 ...
- 记开发个人图书收藏清单小程序开发(十)DB开发——新增图书信息
昨晚完成了Web端新增图书信息的功能,现在就差DB的具体实现了. 因为我把Book相关的信息拆分的比较多,所以更新有点小麻烦. 首先,我需要创建一个Book Type的Matter: 然后,将图片路径 ...
- Entity Framework 更新模式之Attach与EntityState.Modified模式的区别
数据库中有一个City表 初始时数据: 实体类与Fluent Api配置映射 public class City { public int Id { get; set; } public string ...
- [翻译] ZCSHoldProgress
ZCSHoldProgress 以下是使用效果: https://github.com/zshannon/ZCSHoldProgress "Your users be pressin' lo ...
- python2.7与3.5共存windows平台安装
文:铁乐与猫 2018-3-18 周日 01.首先是安装python2.7: 官网下载 https://www.python.org 点击安装包进行安装 可以选择自定义的路径 将默认打x的[add p ...
- Git Hooks、GitLab CI持续集成以及使用Jenkins实现自动化任务
Git Hooks.GitLab CI持续集成以及使用Jenkins实现自动化任务 前言 在一个共享项目(或者说多人协同开发的项目)的开发过程中,为有效确保团队成员编码风格的统一,确保部署方式的统一, ...
- JAVA 泛型通配符 ? EXTENDS SUPER 的用法
1. <? extends Hero> ArrayList heroList<? extends Hero> 表示这是一个Hero泛型或者其子类泛型heroList 的泛型可能 ...
- ansible-playbook快速入门
一.yaml语法: 1. yaml语法编写 1.1 同层级的字段通过相同缩进表示 1.2 map结构里面key/value用‘:’来分隔 1.3 key/value可以同行写,也可以换行写,换行写必须 ...
- Day4 MySql触发器视图索引以及设计优化
触发器 MySQL包含对触发器的支持.触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将调用该对象,即表的操作事件触发表上的触发器的执行. 通过事件触发,不能传参 语法 CREA ...
- 看完了红米5 Plus发布会,我觉得魅蓝Note6降价降多了
没有意外,红米5 Plus在今天下午已经发布.这款以全面屏为卖点的手机机,将红米最低端的一个系列加价到了999元起步——这一切只是因为一个全面屏而已. 知道了红米5 Plus的售价之后,李楠大呼“降多 ...