现在聊一下RabbitMQ消息持久化:

问题及方案描述

1.当有多个消费者同时收取消息,且每个消费者在接收消息的同时,还要处理其它的事情,且会消耗很长的时间。在此过程中可能会出现一些意外,比如消息接收到一半的时候,一个消费者死掉了。

这种情况要使用消息接收确认机制,可以执行上次宕机的消费者没有完成的事情。

2.在默认情况下,我们程序创建的消息队列以及存放在队列里面的消息,都是非持久化的。当RabbitMQ死掉了或者重启了,上次创建的队列、消息都不会保存。

这种情况可以使用RabbitMQ提供的消息队列的持久化机制。

相关理论描述

RabbitMQ支持消息的持久化,也就是数据写在磁盘上,为了数据安全考虑,我个人觉得大多数开发人员都会选择持久化。

队列和交换机有一个创建时候指定的标志durabledurable的唯一含义就是具有这个标志的队列和交换机会在重启之后重新建立,它不表示说在队列当中的消息会在重启后恢复。

消息队列持久化包括3个部分:

1、exchange持久化,在声明时指定durable => true
2、queue持久化,在声明时指定durable => true
3、消息持久化,在投递时指定delivery_mode=> 2(1是非持久化)

如果exchange和queue都是持久化的,那么它们之间的binding也是持久化的。如果exchange和queue两者之间有一个持久化,一个非持久化,就不允许建立绑定。

注意:一旦创建了队列和交换机,就不能修改其标志了。例如,如果创建了一个non-durable的队列,然后想把它改变成durable的,唯一的办法就是删除这个队列然后重现创建

程序示例

生产者

class Producter
{
const string ExchangeName = "eric.exchange";
const string QueueName = "eric.queue";
static void Main(string[] args)
{
var factory = new ConnectionFactory() { HostName = "localhost", UserName = "eric", Password = "", };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);//声明消息队列,且为可持久化的
channel.QueueDeclare(QueueName, durable: true, exclusive: false, autoDelete: false, arguments: null);//声明消息队列,且为可持久化的
channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName); string message = "Eric is very handsome";
var body = Encoding.UTF8.GetBytes(message); //将队列设置为持久化之后,还需要将消息也设为可持久化的
var props = channel.CreateBasicProperties();
props.SetPersistent(true); channel.BasicPublish(ExchangeName, routingKey: QueueName, basicProperties: props, body: body); Console.WriteLine("Producter Sent: {0}", message);
Console.ReadKey();
}
}
}

注:ack是 acknowledgments 的缩写,noAck 是("no manual acks")

因为我前段时间换了笔记本,所以用户的“eric”的操作出踩了个坑,下面进行介绍下:

如果调试运行时报错:None of the specified endpoints were reachable

innerException是:

{"The AMQP operation was interrupted: AMQP close-reason, initiated by Library, code=541, text=\"Unexpected Exception\", classId=0, methodId=0, cause=System.IO.IOException: 无法从传输连接中读取数据: 远程主机强迫关闭了一个现有的连接。。 ---> System.Net.Sockets.SocketException: 远程主机强迫关闭了一个现有的连接。\r\n   在 System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)\r\n   在 System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)\r\n   --- 内部异常堆栈跟踪的结尾 ---\r\n   在 RabbitMQ.Client.Impl.Frame.ReadFrom(NetworkBinaryReader reader)\r\n   在 RabbitMQ.Client.Impl.SocketFrameHandler.ReadFrame()\r\n   在 RabbitMQ.Client.Framing.Impl.Connection.MainLoopIteration()\r\n   在 RabbitMQ.Client.Framing.Impl.Connection.MainLoop()"}

这说明我们使用的用户 不是 系统默认的 guest 而是我们自己创建的用户,但是没有足够的权限进行操作。

解决办法:

rabbitmqctl set_user_tags username administrator
rabbitmqctl set_permissions -p / username ".*" ".*" ".*"

执行结果:

相关其他操作见:windows下 安装 rabbitMQ 及操作常用命令

程序运行结果:

消费者

class Recevice
{
const string ExchangeName = "eric.exchange";
const string QueueName = "eric.queue";
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost", UserName = "eric", Password = "", VirtualHost = "/" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.ExchangeDeclare(ExchangeName, "direct", durable: true, autoDelete: false, arguments: null);//声明消息队列,且为可持久化的
channel.QueueDeclare(QueueName, durable: true, exclusive: false, autoDelete: false, arguments: null);//声明消息队列,且为可持久化的
channel.QueueBind(QueueName, ExchangeName, routingKey: QueueName); BasicGetResult msgResponse = channel.BasicGet(QueueName, noAck: true);
//NoAck:true 告诉RabbitMQ立即从队列中删除消息,另一个非常受欢迎的方式是从队列中删除已经确认接收的消息,可以通过单独调用BasicAck 进行确认:
//BasicGetResult msgResponse = channel.BasicGet(QueueName, noAck:false);
var msgContent = Encoding.UTF8.GetString(msgResponse.Body); Console.WriteLine("The received content:"+msgContent); channel.BasicAck(msgResponse.DeliveryTag, multiple: false);
//使用BasicAck方式来告之是否从队列中移除该条消息
//需要额外注意,比如从队列中获取消息并用它来操作数据库或日志文件时,如果出现操作失败时,则该条消息应该保留在队列中,只到操作成功时才从队列中移除。
Console.ReadKey();
}
}
}

接受消息还有一种方法,就是通过基于推送的事件订阅。可以使用内置的 QueueingBasicConsumer 提供简化的编程模型,允许在共享队列上阻塞,直到收到一条消息。

var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume(QueueName, noAck: true, consumer: consumer);
var msgResponse = consumer.Queue.Dequeue();
var msgContent = Encoding.UTF8.GetString(msgResponse.Body);

程序运行结果:

参考:http://www.cnblogs.com/shanyou/p/4067250.html

RabbitMQ原理与相关操作(三)消息持久化的更多相关文章

  1. RabbitMQ原理与相关操作(二)

    接着 上篇随笔 增加几个概念: RabbitMQ是一个在AMQP(高级消息队列协议)标准基础上完整的,可服用的企业消息系统. AMQP模型的功能组件图(上图摘自 Sophia_tj 的 第2章 AMQ ...

  2. RabbitMQ原理与相关操作(一)

    小编是菜鸟一枚,最近想试试MQ相关的技术,所以自己看了下RabbitMQ官网,试着写下自己的理解与操作的过程. 刚开始的第一篇,原理只介绍 生产者.消费者.队列,至于其他的内容,会在后续中陆续补齐. ...

  3. RabbitMQ(三):消息持久化策略

    原文:RabbitMQ(三):消息持久化策略 一.前言 在正常的服务器运行过程中,时常会面临服务器宕机重启的情况,那么我们的消息此时会如何呢?很不幸的事情就是,我们的消息可能会消失,这肯定不是我们希望 ...

  4. Git相关操作三

    1.显示当前分支: git branch 输入上述命令可以显示出分支,*所在的分支为当前分支. 2.新建分支: git branch new_branch new_branch为新建分支的名称,注意该 ...

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

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

  6. 轻松搞定RabbitMQ(三)——消息应答与消息持久化

    转自 http://blog.csdn.net/xiaoxian8023/article/details/48710653 这个官网的第二个例子中的消息应答和消息持久化部分.我把它摘出来作为单独的一块 ...

  7. rabbitmq消息队列,消息发送失败,消息持久化,消费者处理失败相关

    转:https://blog.csdn.net/u014373554/article/details/92686063 项目是使用springboot项目开发的,前是代码实现,后面有分析发送消息失败. ...

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

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

  9. 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)

    RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

随机推荐

  1. C#中ToString格式大全

    更多资源:http://denghejun.github.io C 货币 2.5.ToString("C") ¥2.50 D 十进制数 25.ToString("D5&q ...

  2. radio相关

    radio 按钮组, name=”sex”. <input type="radio" name="sex" value="Male"& ...

  3. 微软“.Net社区虚拟大会”dotnetConf2015 第二天 无处不在的Xamarin

    今天,微软召开了“.Net 社区虚拟大会”(dotnetConf),包括微软的 Scott Hanselman 和 Xamarin 的 Miguel De Icaza 在内的知名人士,都将在 Chan ...

  4. js问题杂记

    1.如何把字符串数组 转成数组对象? eval妙用 var str = "[\"UserName=1,Pwd=1\",\"UserNmae=1,Pwd=1,Sa ...

  5. ABP理论学习之通知系统

    返回总目录 本篇目录 介绍 订阅通知 发布通知 用户通知管理者 实时通知 通知存储 通知定义 介绍 通知(Notification)用于告知用户系统中的特定事件.ABP提供了基于实时通知基础设施的发布 ...

  6. 送干货,实用内联gulp插件——gulp-embed

    现在npm上有很多gulp内联工具,用于把脚本和样式内嵌到HTML页面上,之前搞项目我也在这些插件中寻觅许久,但均不满足公司项目的一个需求—— HTML上同时插入了开发(dev版,src文件夹下,比如 ...

  7. 递归算法经典实例小结(C#实现)

     一 .递归算法简介 在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法. 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往 ...

  8. 掀起你的盖头来:Unit Of Work-工作单元

    写在前面 阅读目录: 概念中的理解 代码中的实现 后记 掀起了你的盖头来,让我看你的眼睛,你的眼睛明又亮呀,好像那水波一模样:掀起了你的盖头来,让我看你的脸儿,看看你的脸儿红又圆呀,好像那苹果到秋天. ...

  9. Python读取二进制文件

    import os import sys import socket mypath = sys.argv[1] if not os.path.exists(mypath): print "T ...

  10. 学习SpringMVC——从HelloWorld开始

    前言: 时隔十二年,中国女排最终过关斩将,用3:1的成绩证明了自己的实力,霸气夺冠,为中国赢得了一枚意义非常的金牌.这是一次全民的狂欢,一场视听盛宴,带给我们不仅是熠熠生辉的金牌,更传递出的是一种女排 ...