声明

本文欢迎转载,系博主原创,本文原始链接地址:http://www.cnblogs.com/DjlNet/p/7654902.html


前言

此文章,是承接上篇:【框架学习与探究之消息队列--EasyNetQ(1)】未完待续篇,依然对消息队列及其应用的一个补充说明和一些博主的见解。这里说一点废话:就博主自身所见而言的话还有后面了解,现在招聘说明当中部分虽然没有明确提出关于消息队列方面的需求,但是面试官看见几年工作经验的你肯定会多多少少问问关于对此的认识和见解,所以当你以一种颇为了解与实战的姿态说出自己的看法的时候,相信肯定会对这场面试的你加分不少的呐,从而也说明了现今开发当中消息队列的重要性,说到底,它RabbitMQ/EasyNetQ如果能给你带来加分的筹码以及薪资的提升,学习它何乐而不为呐!!!或许这就是面向工资编程吧!!


继续EasyNetQ文档划重点与测试

这里再次强调在基于系统之间的消息交互开发方面,尤其需要注意的就是消息的Publish/Consumer的两种操作的强制落地的思考与解决方案,博主在上文做出一定的见解和实际操作方案。

4、关于交换机的Type以及命名、消息队列的命名

这里如果使用了EasyNetQ框架的情况下(如其名字一样为了简单使用使用了约束),框架会产生如下约束:1、发布订阅的消息必须是.NET Class类型,且类似与DTO一样Public访问修饰符和默认的构造函数没有方法 2、根据消息的类型来进行路由选择。这里首先要说明的是,交换机的名字默认情况就是:因为上面的约定,所以例如当我们的消息定义为public class TextMessage{}的时候,那么默认情况所产生交换机的名字就是:Messages.TextMessage:Messages类型的全名称:程序集的名字并且Exchange类型指定为了Topic,这里需要说明一下就是在几种交换机类型当中,Topic是最灵活可以变相的通过它实现其他类型的工作方式,所以我们的EasyNetQ直接指定该工作类型为了简单化的使用原则;接下来在消费者去订阅该消息的时候默认情况产生队列的名字就是:Messages.TextMessage:Messages_{YourSubscriptionId} 这里YourSubscriptionId可以为empty那么产生的队列名字就会与交换机同名了。

那么框架这里提供这个YourSubscriptionId玩意儿给使用者是干吗使用的呐?

这里博主的理解就是有这个功能点的实现,多半是有这方面的需求,例如当我们需要一个交换机绑定多个队列,但是使用的消息格式是同一个.NET类型,这里就可使用自定义的SubscriptionId来实现多队列多消费者模式,例如日志分发消息系统的需求,也可以当这个标记符来当做类似与模块或者系统的标记达到一看见队列的名字就知道消费者的创建者,等等一些具有意义的标记,切记注意最大字符个数225,还有一点就是如何实现工作队列模式?这里只需要重复订阅同一个消息类型且SubscriptionId一致即可实现多个消费者对同一个队列的共同消费模式,例如当出现既有的消费者已经满足不了处理效率支持的情况下,但是又不想改动原先系统的情况,就可以实现无痛式的增加一个消费者来共同消费达到负载均衡的效果,以及诸如此类的场景。注意:当订阅者消息类型一致的时候,SubscriptionId不同的话就会形成消息复制分发的效果

当然拉,如果想实现更改默认的框架约束自定义交换机和队列名字,参考如下(博主实验证明可行):

[Queue("TestMessagesQueue", ExchangeName = "MyTestExchange")]
public class TestMessage
{
public string Text { get; set; }
}

但是这里一般情况博主认为,就如同代码就是最好的注释一样,让消息类型作为消息队列的名字也是一种不错的解决方案,有一种自圆其说的感觉,从而也印证了框架作者如出一辙的想法就是采用消息类型路由的做法


5、主题路由与消息过滤

这里主要就是交换机的类型了Topic使用了,这里具体的解释与使用参考第一篇文中给出的地址,这里博主需要说明的是框架中注意点当多个消费者指定了相同的消息类型且指定相同的SubscriptionId,那么这些消费者就算是指定了自己的WithTopic也不会达到消息过滤的效果,因为Topic的RouteKey是作用于交换机与队列的不是消息本身,那么既然消费者们都已经是消费同一个队列了那肯定就不会产生消息的过滤了

那么在此框架中提供topic有什么其他用途么,我该怎么使用呐

这里我们依然采用举例子(当然可能例子有些牵强为了迎合我们的topic功能点)的方式来说明,假设我们现在有性能监控系统(A)、日志处理报警系统(B),这里我们其他应用系统底订单系统、库存系统、财务系统等产生的性能安全错误相关消息日志都会统统就发送到A,然后由A分析和挑选出需要转发到B的消息以LogInfoMessage的方式统一推送到MQServer当中,这里使用了同一个消息类型就意味着同一个交换机,这里Publish的时候根据不同携带了不同的RouteKey,例如订单系统->Order.Create、Order.Cancel等等,库存系统->Inventory.Adjust、Inventory.Delivery等等,诸如此类的路由键,然后假设我们的B系统有LogInfoMessage的消费者们,它们可能并不需要关心所有的日志消息,例如OrderLogInfoMessageConsumer只关心订单相关的,配置为 WithTopic("Order.#"),类似InventoryLogInfoMessageConsumer只关心库存相关的日志,配置为了 WithTopic("Inventory.#"),且消费者需要指定唯一的标识,这样一来将会形成一个交换机绑定了多个多个队列以及各自的消费者们,具体参考如下:



上图是关于RabbitMQ交换机的bindings配置图也说说明了问题,这样一来就可以实现同一个消息类型也可以实现消息的按需求过滤式消费了,参考配置对应代码:

例子发布者代码如图
:



例子消费者代码如下

bus.Subscribe<LogInfoMessage>(string.Empty, x => Console.WriteLine(x.Body + " " + x.Creator));
bus.Subscribe<LogInfoMessage>("Order", x => Console.WriteLine(x.Body + " " + x.Creator), x => x.WithTopic("Order.#"));
bus.Subscribe<LogInfoMessage>("Inventory", x => Console.WriteLine(x.Body + " " + x.Creator), x => x.WithTopic("Inventory.#"));
bus.Subscribe<LogInfoMessage>("Finance", x => Console.WriteLine(x.Body + " " + x.Creator),x => x.WithTopic("Finance.#"));
bus.Subscribe<LogInfoMessage>("Order_Inventory", x => Console.WriteLine(x.Body + " " + x.Creator),x => x.WithTopic("Order.#").WithTopic("Inventory.#"));

以上例子便展示topic的应用场景和使用规则,这与上面讲到的SubscriptionId有一定关系,它产生了不同的队列才得以实现不同的队列用不同的routekey来绑定交换机才足以实现消息可以根据自定规则投递到对应的队列当中去


6、自动订阅者划重点

这里EasyNetQ,可以使用它来轻松扫描实现IConsume 或IConsumeAsync 的接口的类的特定程序集,然后自动将这些消费者订阅到RabbitMQ中去。 IConsume 的实现将使用总线Subscribe方法,而IConsumeAsync 的实现将使用总线SubscribeAsync方法。

1、一个消费者可以实现多个泛型消费接口或者异步的泛型消费接口,就可以实现承担消费多种类型的消息的功能

2、[ForTopic("Topic.Foo")]使用该标签在 实现类的方法上面就可以实现与普通订阅使用withtopic同样的效果

3、[AutoSubscriberConsumer(SubscriptionId = "MyExplicitId")] 为消费者对应的队列名称后缀

4、通过控制 AutoSubscriber 的构造函数的 GenerateSubscriptionId 就可以实现全局自动订阅者的配置项 、ConfigureSubscriptionConfiguration 实现全局消费者的配置

5、[SubscriptionConfiguration(CancelOnHaFailover = true, PrefetchCount = 10)] 控制消费者配置,作用于实现类的方法上面

6、替换 AutoSubscriber 的 MessageDispatcher 可以实现我们自定义消费者生产逻辑


总结

**通过第二篇文章我们再一次了解了如何通过框架去了解RabbitMq,以及使用和注意事项,当然这个离我们正真使用到项目集成到系统当中去还有一定的距离,不过相信阅读了这两篇文章的园友,应该还是有所收获,这里博主不光光是只是对框架做了一定的分许和解读,主要还是对rabbitmq本身一些注意点和特性机制做了一定实验研究,也从消息落地方面做了一定设想,这样在改善现有系统和以后新系统的搭建的时候能够做到心中有数的话也是起到了一定的作用了。这里抛出两个问题,也是博主后续将会去了解,1、就目前而言项目中发生了,消息的无故重发,因为隔离了系统的耦合性,导致消息内容一致却被重复处理的问题?提示:做到消息内容处理的幂等验证,不能依赖发送方的可靠性 2、关于如何搭建集群的rabbitmq服务与使用easynetq访问?集群搭建上文有参考链接,这里给出easynetq关于cluster support参考链接:https://github.com/EasyNetQ/EasyNetQ/wiki/Cluster-Support **

如果上述内容对您来说有一定作用的话,您的点赞和评论都是对博主最大的支持的呐,O(∩_∩)O嗯!

【框架学习与探究之消息队列--EasyNetQ(2)】的更多相关文章

  1. 【框架学习与探究之消息队列--EasyNetQ(1)】

    前言 本文欢迎转载,实属原创,本文原始链接地址:http://www.cnblogs.com/DjlNet/p/7603554.html 废话 既然都是废话了,所以大家就可以跳过了,这里是博主有事没事 ...

  2. 深入剖析 RabbitMQ —— Spring 框架下实现 AMQP 高级消息队列协议

    前言 消息队列在现今数据量超大,并发量超高的系统中是十分常用的.本文将会对现时最常用到的几款消息队列框架 ActiveMQ.RabbitMQ.Kafka 进行分析对比.详细介绍 RabbitMQ 在 ...

  3. enode框架step by step之消息队列的设计思路

    enode框架step by step之消息队列的设计思路 enode框架系列step by step文章系列索引: enode框架step by step之开篇 enode框架step by ste ...

  4. 【框架学习与探究之宿主服务--Topshelf】

    前言 此文欢迎转载,原始链接地址:http://www.cnblogs.com/DjlNet/p/7603819.html 正文 原先也偶然见过这个关键词,当时只是有个大致了解貌似和WinServic ...

  5. 【框架学习与探究之定时器--Hangfire】

    声明 本文欢迎转载,请注明文章原始出处:http://www.cnblogs.com/DjlNet/p/7603632.html 前言 在上篇文章当中我们知道关于Quartz.NET的一些情况,其实博 ...

  6. 【框架学习与探究之日志组件--Log4Net与NLog】

    前言 本文欢迎转载,作者原创地址:http://www.cnblogs.com/DjlNet/p/7604340.html 序 近日,天气渐冷,懒惰的脑虫又开始作祟了,导致近日内功修炼迟迟未能进步,依 ...

  7. Redis学习之实现优先级消息队列

    很久没有写博客了,最近简单的学习了一下Redis,其中学习了一下用Redis实现优先级消息队列.关于更多更为详细的可以在www.redis.cn找到相关资料. 对于熟悉Redis的童鞋提到队列很自然的 ...

  8. C# .net 使用rabbitmq消息队列——EasyNetQ插件介绍

    EasyNetQ 是一个简洁而适用的RabbitMQ .NET类库,本质上是一个在RabbitMQ.Client之上提供服务的组件集合.

  9. 【框架学习与探究之定时器--Quartz.Net 】

    声明 本文欢迎转载,原文地址:http://www.cnblogs.com/DjlNet/p/7572174.html 前言 这里相信大部分玩家之前现在都应该有过使用定时器的时候或者需求,例如什么定时 ...

随机推荐

  1. 猎八哥浅谈MYSQL触发器

    什么是MYSQL触发器,我们先了解一下触发的意思.触发的字面意思是指因触动而激发起某种反应. MYSQL必知必会中对触发器的解释是:MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于 B ...

  2. 九度OJ 1016 火星A+B AC版

    #include <iostream> #include <string.h> #include <sstream> #include <math.h> ...

  3. 关于Linux中cd的一些快捷用法

    cd 命令使用的一些小技巧 cd 进入主目录 cd ~ 同样进入主目录 cd - 返回当前目录之前所在的目录 cd .. 返回上级目录 cd ../.. 返回上级的上级目录 cd !$ 把上个命令的参 ...

  4. 对#ifndef的理解

    由于对#ifndef的用法不太理解,在询问了老师#ifndef的含义以及查找资料后,对#ifndef总结了以下几点: <1> #ifndef是宏定义的一种,是三种预处理功能(宏定义,文件包 ...

  5. 【Alpha阶段】第五次 Scrum Meeting

    每日任务 1.本次会议为第 五次 Meeting会议: 2.本次会议在上午09:35,大课间休息时间在陆大召开,召开本次会议为20分钟,汇报自己的任务和讨论接下来的任务: 一.今日站立式会议照 二.每 ...

  6. 201521123019 《Java程序设计》第3周学习总结

    1. 本周学习总结 2. 书面作业 (1)代码阅读 public class Test1 { private int i = 1;//这行不能修改 private static int j = 2; ...

  7. java第二次实验

    1. 本章学习总结 答:学会在java中使用函数调用. 学会在Java程序中使用函数,使程序层次更清晰. 使用StringBuilder代替string拼接,减少内存空间的占用. 使用BigDecim ...

  8. Python[小甲鱼008了不起的分支和循环2]

    案例:对所给的分数进行评级,以下有三种方案: score = int(input('请输入一份分数')) #第一种方案 if 100 >= score >= 90: print('A') ...

  9. 201521123012 《Java程序设计》第十二周学习总结

     作业参考文件 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int ag ...

  10. 读Zepto源码之Selector模块

    Selector 模块是对 Zepto 选择器的扩展,使得 Zepto 选择器也可以支持部分 CSS3 选择器和 eq 等 Zepto 定义的选择器. 在阅读本篇文章之前,最好先阅读<读Zept ...