原文: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(三):消息持久化策略的更多相关文章

  1. RabbitMQ 的消息持久化与 Spring AMQP 的实现剖析

    文章目录 1. 原生的实现方式 2. Spring AMQP 的实现方式   要从奔溃的 RabbitMQ 中恢复的消息,我们需要做消息持久化.如果消息要从 RabbitMQ 奔溃中恢复,那么必须满足 ...

  2. 【python】-- RabbitMQ 队列消息持久化、消息公平分发

    RabbitMQ 队列消息持久化 假如消息队列test里面还有消息等待消费者(consumers)去接收,但是这个时候服务器端宕机了,这个时候消息是否还在? 1.队列消息非持久化 服务端(produc ...

  3. RabbitMQ的消息持久化处理

    1.RabbitMQ的消息持久化处理,消息的可靠性是 RabbitMQ 的一大特色,那么 RabbitMQ 是如何保证消息可靠性的呢——消息持久化. 2.autoDelete属性的理解. 1).@Qu ...

  4. 快速掌握RabbitMQ(三)——消息确认、持久化、优先级的C#实现

    1 消息确认 在一些场合,如转账.付费时每一条消息都必须保证成功的被处理.AMQP是金融级的消息队列协议,有很高的可靠性,这里介绍在使用RabbitMQ时怎么保证消息被成功处理的.消息确认可以分为两种 ...

  5. RabbitMQ原理与相关操作(三)消息持久化

    现在聊一下RabbitMQ消息持久化: 问题及方案描述 1.当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间.在此过程中可能会出现一些意外,比如消息接收 ...

  6. RabbitMQ之消息持久化(转)

    原文地址 https://blog.csdn.net/u013256816/article/details/60875666/ 消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证 ...

  7. RabbitMq初探——消息持久化

    消息持久化 前言 通过上一节,我们知道,有消息确认机制,保证了当消费者进程挂掉后,消息的不丢失. 但是如果rabbitmq挂掉呢?它的队列和消息都会丢失的.为了保证消息在rabbitmq挂掉重启后不丢 ...

  8. RabbitMQ之消息持久化

    消息的可靠性是RabbitMQ的一大特色,那么RabbitMQ是如何保证消息可靠性的呢——消息持久化. 为了保证RabbitMQ在退出或者crash等异常情况下数据没有丢失,需要将queue,exch ...

  9. RabbitMQ之消息持久化(队列持久化、消息持久化)

    rabbitMQ不支持数据库的持久化,只支持内存以及文件持久化 https://blog.csdn.net/bwh0520/article/details/78746873 http://blog.y ...

随机推荐

  1. Linux学习之CentOS(四)----Linux各目录的介绍

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  2. c# 多线程之-- System.Threading Timer的使用

    作用:每隔多久去执行线程里的方法. class ThreadTimerDemo { static void Main(string[] args) { // Create an AutoResetEv ...

  3. 使用 PowerShell 创建和修改 ExpressRoute 线路

    开始之前 安装最新版本的 Azure Resource Manager PowerShell cmdlet. 有关详细信息,请参阅 Azure PowerShell 概述. 在开始配置之前,请查看先决 ...

  4. SQL Server ->> 条件筛选做法之 -- IN(VALUE1,VALUE2,...)与INNER JOIN STRING_SPLIT()性能对比

    在以逗号拼接而成的字符串,传入给IN字句的元素字符串中包涵了1400多个元素 两种做法分别为 AND e.ssPfCityId IN ( SELECT CAST(value AS INT) FROM ...

  5. 用以替换系统NSLog的YouXianMingLog

    用以替换系统NSLog的YouXianMingLog 这是本人自己使用并改良的用以替换系统NSLog的类,非常好用,以下是使用示例,现在开源出来并提供源码,好用的话顶一下吧^_^ 效果: YouXia ...

  6. Linux 系统的用户和组详解_【all】

    1.Linux 用户和用户组详解 2.Linux 文件特殊权限详解 3.Linux 文件的读写执行权限的说明 4.Linux 架构之简述企业网站 5.Linux 环境变量设置详解 6.企业生产环境用户 ...

  7. September 20th 2017 Week 38th Wednesday

    All our dreams can come true if we have the courage to pursue them. 如果我们有勇气去追求梦想,我们的梦想一定可以成为现实. If y ...

  8. 高性能网站架构缓存——redis集群

    相信你已经对redis有一定的了解,并能够安装上,进行简单的使用了,但是在咱们的实际应用中,使用redis肯定不会使用单机版,不光是redis不能使用单机版,其他的也不会使用,所以今天我们来说一下re ...

  9. C++浅拷贝和深拷贝的区别

    C++浅拷贝和深拷贝的区别 2012-04-24 21:22 11454人阅读 评论(6) 收藏 举报 c++deleteclass编译器c c++默认的拷贝构造函数是浅拷贝 浅拷贝就是对象的数据成员 ...

  10. arcgis 10.1 导入数据到oracle 发布地图服务

    机器配置说明 数据库服务器 系统:linux 软件:oracle 11G 64位 Arcgis server服务器 系统:win7 专业版 软件:arcgis server 10.1.win64_11 ...