RabbitMQ及延时队列
一、简介
我用过RabbirMQ的发布订阅模式,以及一对一的延迟队列。
1、RabbitMQ的有消息确认机制,消费一条则队列中少一条,也有对应的消费到消息及认为是消费成功这样的模式,一般使用前者。
发布订阅我是在处理大量数据的更新及与其他系统有数据来往时使用的。在本地程序处理一条则发送一条到队列,保证本地处理成功并发送到其他系统。
延迟队列这种模式也是在与其他系统有交互并且在我这边系统接到成功后必须不马上发给其他的系统,如果在多少时间内本地没有接到说不发的指令才有延迟队列转发到其他系统。
安装部署简介及可视化页面:
https://www.cnblogs.com/Leo_wl/p/5402125.html
2、在c#中的使用
NuGet引用:RabbitMQ.Client
2.1 发布消息
2.1 .1发布订阅
public static void PublishMsgString(IConnection conn, string message, PublishMsgModel model, IDictionary<string, object> headerDict)
{
try
{
using (var channel = conn.CreateModel())
{
channel.ExchangeDeclare(exchange: model.ExchangeName, type: model.ExchangeType, durable: model.Durable);
channel.QueueDeclare(queue: model.QueueName, durable: model.Durable, exclusive: false, autoDelete: false, arguments: null);
channel.QueueBind(queue: model.QueueName, exchange: model.ExchangeName, routingKey: model.RouteKey);
var properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2;
if (headerDict != null)
{
properties.Headers = headerDict;
properties.ContentType = "text/plain";
properties.ContentEncoding = "UTF-8";
}
//string messageString = JsonConvert.SerializeObject(message);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.ConfirmSelect();
channel.BasicPublish(model.ExchangeName, model.RouteKey, properties, body);
if (channel.WaitForConfirms())
{
Common.WriteLog($"【Success】【发布消息】[MsgType]{model.MsgType}[messsage]{message}成功", "publish", model.QueueName);
}
else
{
Common.WriteLog($"【Error】【发布消息】[MsgType]{model.MsgType}[messsage]{message}失败", "publish", model.QueueName);
}
}
}
catch (Exception ex)
{
Common.WriteLog($"【Error_Ex】【发布消息】[MsgType]{model.MsgType}发布消息异常:{ex.Message}[message]{message}", "publish", model.QueueName);
}
}
2.1.2、延迟队列
public static void PublishExpirationMsgString(string message, PublishMsgModel model, PublishMsgModel modelExpiration, Dictionary<string, object> headerDict, bool isTest)
{
try
{
ConnectionFactory connFactory = new ConnectionFactory()
{
HostName = isTest ? ConfigurationManager.AppSettings["MQ.HostName.Test"] : ConfigurationManager.AppSettings["MQ.HostName"],
UserName = isTest ? ConfigurationManager.AppSettings["MQ.UserName.Test"] : ConfigurationManager.AppSettings["MQ.UserName"],
Password = isTest ? ConfigurationManager.AppSettings["MQ.Password.Test"] : ConfigurationManager.AppSettings["MQ.Password"],
VirtualHost = isTest ? ConfigurationManager.AppSettings["MQ.VirtualHostLog.Test"] : ConfigurationManager.AppSettings["MQ.VirtualHostLog"],
Port = int.Parse(isTest ? ConfigurationManager.AppSettings["MQ.Port.Test"] : ConfigurationManager.AppSettings["MQ.Port"]),
AutomaticRecoveryEnabled = true,
RequestedHeartbeat = 30
};
using (IConnection conn = connFactory.CreateConnection())
{
using (var channel = conn.CreateModel())
{
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("x-expires", 4 * 1000 * 60);
dic.Add("x-message-ttl", 3 * 1000 * 60);//队列上消息过期时间,应小于队列过期时间
dic.Add("x-dead-letter-exchange", model.ExchangeName);//过期消息转向路由
dic.Add("x-dead-letter-routing-key", model.RouteKey);//过期消息转向路由相匹配routingkey
channel.QueueDeclare(queue: modelExpiration.QueueName, durable: modelExpiration.Durable, exclusive: false, autoDelete: false, arguments: dic);
channel.ExchangeDeclare(exchange: modelExpiration.ExchangeName, type: modelExpiration.ExchangeType, durable: modelExpiration.Durable);
channel.QueueBind(queue: modelExpiration.QueueName, exchange: modelExpiration.ExchangeName, routingKey: modelExpiration.RouteKey);
var properties = channel.CreateBasicProperties();
properties.DeliveryMode = 2;
if (headerDict != null)
{
properties.Headers = headerDict;
properties.ContentType = "text/plain";
properties.ContentEncoding = "UTF-8";
}
//string messageString = JsonConvert.SerializeObject(message);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.ConfirmSelect();
// properties.Expiration = (2 * 1000 * 60).ToString();
channel.BasicPublish(modelExpiration.ExchangeName, modelExpiration.RouteKey, properties, body);
if (channel.WaitForConfirms())
{
Common.WriteLog($"【Success】【发布消息】[MsgType]{modelExpiration.MsgType}[messsage]{message}", "publish", modelExpiration.QueueName);
}
else
{
Common.WriteLog($"【Error】【发布消息】[MsgType]{modelExpiration.MsgType}[messsage]{message}失败", "publish", modelExpiration.QueueName);
}
}
}
}
catch (Exception ex)
{
Common.WriteLog($"【Error_Ex】【发布消息】[MsgType]{modelExpiration.MsgType}发布消息异常:{ex.Message}[message]{message}", "publish", modelExpiration.QueueName);
}
}
2.2消费消息
public static string GetConfig(string key)
{
return ConfigurationManager.AppSettings[key];
}
public static bool IsTest
{
get { return (ConfigurationManager.AppSettings["IsTest"] ?? "") == "1"; }
}
private static ConnectionFactory connFactory = new ConnectionFactory()
{
HostName = IsTest ? GetConfig("MQ.HostName.Test") : GetConfig("MQ.HostName"),
UserName = IsTest ? GetConfig("MQ.UserName.Test") : GetConfig("MQ.UserName"),
Password = IsTest ? GetConfig("MQ.Password.Test") : GetConfig("MQ.Password"),
VirtualHost = IsTest ? GetConfig("MQ.VirtualHost.Test") : GetConfig("MQ.VirtualHost"),
Port = int.Parse(IsTest ? GetConfig("MQ.Port.Test") : GetConfig("MQ.Port")),
AutomaticRecoveryEnabled = true,
RequestedHeartbeat = 30
};
private static IConnection conn = connFactory.CreateConnection();
private static IModel channel = conn.CreateModel();
private const string queueAllOrder = "user_order_idex_to_log";
private static EventingBasicConsumer consumerOrder,;
private static void ListenMQ(object queue)
{
string[] queueInfo = (string[])queue;
string queueName = queueInfo[0];
string nowThread = queueInfo[1];
PublishMsgModel model = new PublishMsgModel() { Durable = true, ExchangeName = queueName, ExchangeType = ExchangeType.Direct, QueueName = queueName, RouteKey = queueName, MsgType = "" };
channel.BasicQos(0, 1, false);
channel.QueueDeclare(queue: model.QueueName, durable: model.Durable, exclusive: false, autoDelete: false, arguments: null);
switch (queueName)
{
case queueOrder:
model.MsgType = "test";
consumerOrder = new EventingBasicConsumer(channel);
consumerOrder.Received += ConsumOrderMsg;
channel.BasicConsume(model.QueueName, false, consumerOrder);//消费确认,逐条
break;
}
}
private static void ConsumOrderMsg(object sender, BasicDeliverEventArgs eventArgs)
{
string logName = "order_idex_to_devcenter";
try
{
byte[] body = eventArgs.Body;
if (body != null && body.Length > 0)
{
string message = Encoding.UTF8.GetString(body);
++consumOrderMessageTotalOrder;
string msgType = Encoding.UTF8.GetString((byte[])eventArgs.BasicProperties.Headers["messageType"]),
msgId = Encoding.UTF8.GetString((byte[])eventArgs.BasicProperties.Headers["messageId"]), userId = Encoding.UTF8.GetString((byte[])eventArgs.BasicProperties.Headers["userId"]);
}catch{}
}
RabbitMQ及延时队列的更多相关文章
- 基于rabbitMQ 消息延时队列方案 模拟电商超时未支付订单处理场景
前言 传统处理超时订单 采取定时任务轮训数据库订单,并且批量处理.其弊端也是显而易见的:对服务器.数据库性会有很大的要求,并且当处理大量订单起来会很力不从心,而且实时性也不是特别好 当然传统的手法还可 ...
- rabbitMq实现延时队列
原文:https://my.oschina.net/u/3266761/blog/1926588 rabbitMq是受欢迎的消息中间件之一,相比其他的消息中间件,具有高并发的特性(天生具备高并发高可用 ...
- RabbitMq 实现延时队列-Springboot版本
rabbitmq本身没有实现延时队列,但是可以通过死信队列机制,自己实现延时队列: 原理:当队列中的消息超时成为死信后,会把消息死信重新发送到配置好的交换机中,然后分发到真实的消费队列: 步骤: 1. ...
- 【日常摘要】- RabbitMq实现延时队列
简介 什么是延时队列? 一种带有延迟功能的消息队列 过程: 使用场景 比如存在某个业务场景 发起一个订单,但是处于未支付的状态?如何及时的关闭订单并退还库存? 如何定期检查处于退款订单是否已经成功退款 ...
- rabbitmq实现延时队列(死信队列)
基于队列和基于消息的TTL TTL是time to live 的简称,顾名思义指的是消息的存活时间.rabbitMq可以从两种维度设置消息过期时间,分别是队列和消息本身. 队列消息过期时间-Per-Q ...
- Rabbitmq的延时队列的使用
配置: spring: rabbitmq: addresses: connection-timeout: username: guest password: guest publisher-confi ...
- rabbitmq 安装延时队列插件rabbitmq-delayed-message-exchange
1.下载rabbitmq-delayed-message-exchange(注意版本对应) 链接:https://github.com/rabbitmq/rabbitmq-delayed-messag ...
- IOS IAP 自动续订 之 利用rabbitmq延时队列自动轮询检查是否续订成功
启用针对自动续期订阅的服务器通知: - 官方地址: - https://help.apple.com/app-store-connect/#/dev0067a330b - 相关字段, 相关类型地址: ...
- 面试官:RabbitMQ过期时间设置、死信队列、延时队列怎么设计?
哈喽!大家好,我是小奇,一位不靠谱的程序员 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 文章持续更新 一.前言 RabbitMQ我们经常的使用, ...
随机推荐
- Java 多线程实现方式三:实现 Callable 接口
完整套路 java 通过实现Callable 接口来实现多线程相比较于继承Thread 接口和 实现Runnable 接口比较麻烦,但好处是可以有返回值. 基本套路: 1. 创建目标对象 2. 创建执 ...
- 理解java容器底层原理--手动实现HashMap
HashMap结构 HashMap的底层是数组+链表,百度百科找了张图: 先写个链表节点的类 package com.xzlf.collection2; public class Node { int ...
- caddy配置php-fpm
特码的,谷歌又用不了了. 吐槽完毕,正文如下: caddy是一个用go语言开发的服务器,可用作web端. caddy本身支持 -conf caddyfile的配置 在命令行中的体现: caddy -c ...
- LeetCode 面试题56 - I. 数组中数字出现的次数 | Python
面试题56 - I. 数组中数字出现的次数 题目 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度是O(n),空间复杂度是O(1). ...
- 如何在Vue项目中优雅的使用sass
开始之前,请先确保有一个基于webpack模板的项目(vue-cli脚手架一键安装~) 1.打开项目终端,安装sass的依赖包 npm install --save-dev sass-loader / ...
- CCF系列奖获奖名单公布,鲍虎军、周志华获CCF王选奖 | CNCC 2017
本文讲的是CCF系列奖获奖名单公布,鲍虎军.周志华获CCF王选奖 | CNCC 2017, 由中国计算机学会(CCF)主办,福州市人民政府.福州大学承办,福建师范大学.福建工程学院协办的2017中国计 ...
- 强行重装IE6
一句指令解决了郁闷一天的问题: 今天碰到问题如下: 在不知是不是人品问题的情况下(其实基本是优化大师嫌疑最大)发现在第三方引用的软件中不能打开IE了: 具体症状: 在QQ中点击别人的链接,没反应: 在 ...
- 如何将MAC的 Terminal 行首变得清爽简洁一点?
作为一位开发人员,MAC带给我们更好的编程体验,Terminal也是经常会去操作的东西,但是说实话,默认的 Terminal 的各种设置,真的让我好难受 刚开始打开,可能看到的会是这样的,行首一大堆东 ...
- C++--浅谈开发系统的经验
最近写了不少类了,从垃圾代码爬坑,虽然还是很垃圾,但是照葫芦画瓢,有几分神韵.在这里总结一下,写类的经验教训. 第一步 分析: 当拿到一个要求时,要先去考虑怎样一个类到底该实现什么样的功能,有什么样的 ...
- jmeter正则表达式提取多个数据/一组数据时,应该怎么做——debug sampler的使用
背景:今天有个接口需要借助前面接口产生的一组ids数据,来作为入参使用,但是之前都是提取单个接口,所以到底怎么提取接口,遇到了很大的问题,按照多方查取资料都没有成功,最终在一个不相关帖子的最后一句话被 ...