RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践

时间:2023-02-23 17:12:51

EasyNetQ文档跟进式学习与实践

https://www.cnblogs.com/DjlNet/p/7603554.html

这里可能有人要问了,为什么不使用官方的nuget包呐:RabbitMQ.Client(官方还在积极对.net core做升级去兼容.net standrad,这挺好,https://www.nuget.org/packages/RabbitMQ.Client/5.1.0-pre1),要说为什么,其实无非就是原始的官方包你说要用吧也可以用,就是需要学习成本,让小组成员都要熟悉API又是一番功夫且低级API方法不是那么通俗易懂,当然拉有能力的当然可以借助官方包二次封装以适应自己项目或者Team的需求,前提是对交互机制和对原始API有较为全面的了解,所以综上所说呐,在社区的支持下提供了 框架:EasyNetQ,从其名便可以知道,方便了我们使用高阶API的同时,依然保留了对原始高级功能点的访问,所以这也体现框架作者的对框架的理解也基本上足够我们当前的使用需求了,当然了此框架本身也是依赖于 RabbitMQ.Client 的也是一个二次封装的结果,所以呐博主选取它作为学习或者项目集成方面,都不愧是一个不错的选择!相信使用过的老铁,都知道它的好,希望作者延续出core的版本吧.....同时博主不希望只仅仅是简单的跟着文档滚一边,而且想以一种正确优雅的姿势把此消息队列框架集成在系统当中,且巧妙的设计以及避开一些坑,实现在业务与消息之间微妙的关系(例如通过事件总线来统筹,MQ消息来传递),同时保证消息交互一个不稳定的情况下,如何实现尽可能的消息落地与确保,这也是当今面对分布式事务的一种婉转但不失优雅的解决方案.....

EasyNetQ文档划重点与测试

这里是博主认为有必须要视为重点且需要实验验证的点,如若没有提及的地方,可以提出来一起讨论学习

1、发布者确认(Publisher Confirms):简而言之就是确保消息的成功投递,通俗的讲就是我要知道,我投递的消息到底有木有成功被接受。连接字符增加 publisherConfirms=true; 即可,这里博主建议不要为了那么一丢丢的确认性能的考虑而放弃发送消息确认配置,同时为了保证消息的投递成功,RabbitMQ也推荐使用该方式因为没有实现事务方式,且发送消息之后不管是同步方法(Publish)还是异步方法(PublishAsync)在自身内部都会在超时还没到的时间段内,一直等待消息确认接收的反馈讯息,再然后同步方法才会返回,异步方法也会返回一个完成状态的Task对象,当然可能因为网络或者MQServer服务宕机等一系列问题导致同步异常爆发或者异步返回异常的Task对象,所以还需要对后续异常情况处理和日志记录机制的的实施,至此这种发布者确认带来的消息推送保障对于我们的系统来说很重要,关乎到系统交互的责任归属问题(例如:你说你投递成功了,我咋知道你投递成功了没有,我这里没收到啊,这样比较搞笑的对话了)

这里补充说明一点就是,日常开发中博主见过的消息推送目前的两种方式:

a、要求消息的发送与业务逻辑耦合在一个数据库的事务作用域当中,且消息发送需要放在业务逻辑的最后面(你懂的),这样就形成了一个利用数据库层面的强制原子操作,包含消息发送日志记录当作证据,达到消息和业务绑定关系为同生共死“要么都成功,要么都失败”,好处:实现了逻辑的一致性以及消息的及时发送,可以满足某些特殊需求,坏处:消息发送需要远程服务器交互(内网或者外网)需要等待耗时且一定程度拉低了系统处理能力受MQ消息服务器的影响,并且发送失败会导致业务处理失败浪费了前期逻辑处理,所以也不存在消息的重试机制了,直接重新操作业务逻辑就可以重试发送了;当然依然需要异常处理与日志记录

b、将业务逻辑产生的消息归档到一个等待发送消息DB(Table)中做持久化处理,然后通过定时器框架配合处理,轮询取出一定数量应该发送的消息(这里包括没发送成功需要重试的消息,一直怼)到MQServer中成功无异常后重置消息的发送标记位flag=true,重试消息的话RetryCount++,这里当然也是在一个DB事务当中且消息发送依然在尾部逻辑(你懂的),好处:消息发送与业务逻辑分离,职责划分明确增加了系统各自部分的稳定性不受消息服务影响,相互独立不受牵制,且已经具备了消息发送日志记录(前面说的等待发送消息持久化证明)作为证据,坏处:消息发送具有一定得延迟性也就是定时器的间隔时间,同理这方式依然需要异常处理与日志记录

当然以上两种方式都是基于额外数据库事务支持的情况下(加上PublisherConfirms共同保证消息落地性),至于选择何种方式或者是说怎么样来灵活的组合使用,来应对系统消息发布的场景,看上面的解释也能大致有数了吧,其实也需要根据开发时的业务场景、网络、服务器资源等等综合考虑,不过一般情况博主推荐使用方式b即可,一般一般一般情况下对于消息的及时性要求不高,控制在一定的忍耐程度就行了,也是目前博主采取的方式来操作,不过得注意得时相关与网络传输交互都需要异常处理和日志记录来做问题得检查和恢复得支撑,至于上面两种方式的代码集成就比较明显了,毕竟思路明确了,博主这里打算后面框架集成部分给出参考吧。

2、prefetchcount:在RabbitMQServer获取Consumer消费者反馈的ack(确认消费标志)之前,RabbitMQ服务能够分发消息给消费者的最大值,连接字符串配置:prefetchcount=50;,默认是50,且这些消息处于内存队列中处于准备状态,从控制台界面查看就是(注意红框处就是设置值,这里博主测试设置了为:prefetchcount=5;,然后故意让消费者延迟反馈ack确认消息回执)

RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践

测试代码如下:

IBus bus = RabbitHutch.CreateBus("host=localhost;virtualHost=/;username=yourname;password=yourpassword;publisherConfirms=true;timeout=10;prefetchcount=5");
bus.Subscribe<MyClass>(string.Empty, x =>
{
Console.WriteLine(x.Text);
Task.Delay(TimeSpan.FromSeconds(5)).Wait();
});

当然这个配置是作用于消费者,那么这里每个消费者可以自定义该配置来覆盖连接字符串中的全局配置,来达到控制个别消费者的细粒度,参考如下代码与效果图

RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践

RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践

,设置0表示不限制可以无限发送消息(不推荐),设置1表示消费者以公平方式接受消息(多个消费者共享一个队列的时候,消费顺序按照订阅而定),其实说白了,这个值的设定是要看消息接收方处理能力而定的,所以具体生成环境看情况而定吧,采用默认设置也可以。

3、Ack:表示订阅者接受并处理消息之后回执。

例如:一个订阅了MyMessage的订阅者,如果程序崩溃会发生什么?为了提高效率,EasyNetQ实现了一个用于订阅的内部内存队列。消息通过网络从RabbitMQ接收并放置在此队列上。单个订阅线程依次将消息从队列中取出,并将它们传递给您提供的回调。一旦回调完成,EasyNetQ将发送一个“Ack”回RabbitMQ。在收到“Ack”之前,消息不会从RabbitMQ队列中删除。如果您的服务在处理消息时中止,还没有Ack的回传,消息(以及EasyNetQ内存中队列中的所有消息)将保留在RabbitMQ队列中,一旦您的服务重新连接,消息将被重新发送,从上而知也知道ACK的作用和意义。

当然消费消息的时候发生异常:如果您的订阅回调引发EasyNetQException异常,EasyNetQ将会收到正在消费的消息,并将其包装在特殊的错误消息中。错误消息将被发布到EasyNetQ错误队列(名为EasyNetQ_Default_Error_Queue)。您应该监视任何消息的错误队列。错误消息包括重新发布原始消息以及异常类型,消息和堆栈跟踪所需的所有信息。您可以使用EasyNetQ.Hosepipe实用程序重新发布错误消息。请参阅下面的EasyNetQ.Hosepipe部分。

这里默认EasyNetQ已经帮我们做好了消息处理的部分逻辑,包括异常处理和消息ACK回执,

那么我们在生产环境如何保证消费消息做到尽可能消息100%落地?

这里博主的大致解决办法描述如下:这里消息体的格式协定以及消息基本验证什么的,不再讨论方法之类,就如同API方法参考校验一个性质,这里相信大部分订阅者处理消息都参与了数据库逻辑,所以这里博主就必须把传递过来的消息持久化到数据库中当做消费证明,当然这里又可以使用数据库的ACID的事务机制来包裹消息日记录ConsumerLog以及之前的一些业务逻辑数据库写操作或者其他Web请求逻辑,当然可能会由于网络请求或者数据库本身的问题出现爆发异常,导致事务回滚(业务逻辑同时消费消息日志记录失败,这种就是除本身逻辑异常之外的不可控的异常爆发),那么这种还需要进一步保证消息落地怎么办呐?回答:没有百分百的保证,首先还是再一次的向数据库或者NoSql再次写入消息,不过这里是写入异常消费失败的消息ConsumerErrorLog(那么就需要定时器消息重试消费逻辑的机制),如果上述还是不行(因为这里还可能还是失败)就需要文本日志来记录Message消息体做进一步保证了,其次就是Log记录异常原因,最最后我还可以利用上述EasyNetQ提供了EasyNetQException异常机制将消费失败的消息进一步在EasyNetQ错误队列(名为EasyNetQ_Default_Error_Queue)也保留一份存档方便对照查阅,到这里相信基本上能够尽可能保证消息消费的正确姿势了,当然上述思路可能依然并不是最合适的,最好是结合自己的情况进一步定制化自己的消息处理框架吧。

RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践的更多相关文章

  1. Elasticsearch学习系列之多文档操作mget

    测试数据 GET /library/books/1 { "_index": "library", "_type": "books& ...

  2. Qt入门学习——Qt 5 帮助文档的使用

    Qt入门学习——Qt 5 帮助文档的使用 学习图形界面开发,肯定离不开帮助文档的使用,因为它不像 C 语言那样就那么几个函数接口,图形接口的接口可以用海量来形容,常用的我们可能能记住,其它的真的没有必 ...

  3. DocX开源WORD操作组件的学习系列四

    DocX学习系列 DocX开源WORD操作组件的学习系列一 : http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_sharp_001_docx1.htm ...

  4. ElasticSearch 学习记录之 分布式文档存储往ES中存数据和取数据的原理

    分布式文档存储 ES分布式特性 屏蔽了分布式系统的复杂性 集群内的原理 垂直扩容和水平扩容 真正的扩容能力是来自于水平扩容–为集群添加更多的节点,并且将负载压力和稳定性分散到这些节点中 ES集群特点 ...

  5. scrapy爬虫学习系列四:portia的学习入门

    系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备:      http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...

  6. Javascript学习8 - 脚本化文档&lpar;Document对象&rpar;

    原文:Javascript学习8 - 脚本化文档(Document对象) 每个Web浏览器窗口(或帧)显示一个HTML文档,表示这个窗口的Window对象有一个document属性,它引用了一个Doc ...

  7. webservice学习01:wsdl文档结构

    webservice学习01:wsdl文档结构 wsdl文档结构 WSDL文档示例 <wsdl:definitions xmlns:xsd="http://www.w3.org/200 ...

  8. 20165234 &lbrack;第二届构建之法论坛&rsqb; 预培训文档&lpar;Java版&rpar; 学习总结

    [第二届构建之法论坛] 预培训文档(Java版) 学习总结 我通读并学习了此文档,并且动手实践了一遍.以下是我学习过程的记录~ Part1.配置环境 配置JDK 原文中提到了2个容易被混淆的概念 JD ...

  9. ElasticSearch学习之——基本的文档CURD

    一.文档的添加 POST http://127.0.0.1:9200/{index}/{type}/{id} { "key":"value", "ke ...

随机推荐

  1. sass入门教程

    一.什么是SASS SASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护. 二.安装和使用 2.1 安装 SASS是Ruby语言写的,必须先 ...

  2. &lbrack;QualityCenter&rsqb;设置工作流脚本-缺陷字段值发生变化时的处理

    需求:缺陷状态发生不同变化时,系统会的自动处理一些字段值的变化 在脚本编辑器找到Defects_Bug_FieldChange函数,然后填写以下代码: Sub Defects_Bug_FieldCha ...

  3. Objective-C的对象模型和runtime机制

    内容列表 对象模型(结构定义,类对象.元类和实例对象的关系) 消息传递和转发机制 runtime系统功能理解 对象模型 结构定义 对象(Object): OC中基本构造单元 (building blo ...

  4. hdu 1288 Hat&&num;39&semi;s Tea

    这个要慢慢理解…… ;}

  5. 在华为oj的两个月

    一次偶然的机会,我接触到华为oj平台(http://career-oj.huawei.com/exam/camLogin.jsp),当时的心情很是兴奋,于是立马注册开通,然后迫不及待地上去做题.刚开始 ...

  6. tomcat文件夹没有部署项目和Tomcat中webapps中没有运行项目-上传下载文件和图片

    1.eclipse不像MyEclipse默认将项目部署到tomcat安装目录下的webapps中,而默认部署到工作目录下的.metadata.plugins\org.eclipse.wst.serve ...

  7. Vijos 1012 清帝之惑之雍正 平面最近点对(分治)

    背景 雍正帝胤祯,生于康熙十七年(1678)是康熙的第四子.康熙61年,45岁的胤祯继承帝位,在位13年,死于圆明园.庙号世宗. 胤祯是在康乾盛世前期--康熙末年社会出现停滞的形式下登上历史舞台的.复 ...

  8. C&plus;&plus;STL(vector,map,set,list)成员函数整理

    / *最近ACM比赛,用到的时候忘记成员函数了,贼尴尬,给以后比赛做下准备 */ LIST: 构造函数 list<int> c0; //空链表 list<int> c1(3); ...

  9. 开发指南专题六:JEECG微云高速开发平台代码生成

    开发指南专题六:JEECG微云高速开发平台代码生 1.1. 代码生成扫描路径配置 用代码生成器生成代码后.须要进行相关配置配置,扫描注入control.service.entity等; 具体操作过程例 ...

  10. python学习笔记&lpar;十 三&rpar;、网络编程

    最近心情有点儿浮躁,难以静下心来 Python提供了强大的网络编程支持,很多库实现了常见的网络协议以及基于这些协议的抽象层,让你能够专注于程序的逻辑,而无需关心通过线路来传输比特的问题. 1 几个网络 ...