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

前言

本文欢迎转载实属原创,本文原始连接地址:http://www.cnblogs.com/DjlNet/p/7603554.htmlhtml


废话

既然都是废话了,因此你们就能够跳过了,这里是博主有事没事儿的一点瞎说哈,国庆节+中秋节一共8天,有些人回家了,有些人堵在路上了,有些人可能还要加班或者值班,233333,博主这里还好是没有加班通常也不须要值班,可能偶尔须要的时候远程瞅瞅就行。相信不少小伙伴,在放假前夕都作好了要去哪里玩,要去哪里吃,要怎么过好节假日,固然也有要看书的,有假期学习计划,有锻炼身体的,说说本身吧,博主算是综合性了,餐了聚了、黑也开了、电影也看了、书还没看、计划学习搁置+延期了、身体也没啥锻炼、剧却是跟进了一些,看到这里是否是以为博主的生活是否是冥冥之中在哪里见过,对,是的,多多少少量多人都“中招”了(固然了每一个人有本身的理解和生活方式,没有人能够批判谁对谁错,因此,没有对错,只有利弊!!!),说着说着博主放下了手中的“屠刀”,陷入了思考,想着不远千里啊,为了啥,还不仍是为了将来,正当博主思考之际,电话响了起来,外卖:帅哥,您的外卖到了,请麻烦下来拿一下!!!,一个叫阿龙的人,内心若有所思的走下楼拿了外卖回到了电脑前面,打开了S7世界赛的画面津津有味的看起来直播.......以上言语,纯属瞎扯,若有雷同,那也只能这样了,哈哈!!!sql


正文

再说此框架以前呐,有些前提概念或者知识须要了解一下的,念与博主自己这方面知识也有所不足(须要理解充电),因此部分知识只限于提供连接地址和部分理解所悟(可能后面单独出文再加以叙述说明吧),因此园友如若发现不当之处,可尽情提出出来一块儿谈论即是,因为园内不少次框架相关文章,可是或多或少都显得有些零散或者是入门系列不过是咱们做为参考的辅助资料,博主将会集中式整理一些方便查阅,固然此篇文章或许有些入门知识可是更着重的是划出博主认为须要注意的重点项,大体梳理顺序逻辑,仍是按照前提概念知识补充、框架文档与实践、划重点与问题探究....接下来咱们一步一步的扒光式的来学习....数据库


背景

在此以前多多少少就知道一些关于消息队列方面的东西,博主先前的时候就作过一些MSMQ+WCF的项目实践,不过呐这种组合在当前的技术流就显得力不从心,一方面呐部署环境的受限,运维大兄弟对Linux更加的驾轻就熟,再者就是这种组合自己的局限性和开发的坑略多了些,那么基于当前的来作消息交互、解耦、限流或者削锋等一般状况下选择无非就是,当前使用较多的消息队列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMq等,而部分数据库如Redis、Mysql以及phxsql也可实现消息队列的功能。因为咱们主要基于RabbitMQ上面来作说明和研究使用( .NET社区一般的选择也是目前博主公司的选择,因此得先从这下手知其一而百通,哈哈 ),其余状况这里博主找到一篇好文: https://cloud.tencent.com/community/article/129032 消息队列及常见消息队列介绍 ,文中关于消息队列的使用场景和各自的优缺点对比说明都有必定的说明,你们能够跳过去看看,而且文中结尾还有些各自MQ的参考学习连接,也能够做为学习途径......编程

这里博主以为仍是有必要备注一下(引用来自于上文连接):消息队列在实际应用中包括以下四个场景(连接中对每一个场景有举例分析,可参考):
应用耦合:多应用间经过消息队列对同一消息进行处理,避免调用接口失败致使整个过程失败;
异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减小处理时间;
限流削峰:普遍应用于秒杀或抢购活动中,避免流量过大致使应用系统挂掉的状况;
消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;安全


知识前提RabbitMQ

从官网https://www.rabbitmq.com咱们能够得知,它已经走过了10个年头了,是一个在AMQPhttp://www.amqp.org/(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。服务器

这里说明一下RabbitMQ主要特性:
可靠性: 提供了多种技术可让你在性能和可靠性之间进行权衡。这些技术包括持久性机制、投递确认、发布者证明和高可用性机制;
灵活的路由: 消息在到达队列前是经过交换机进行路由的。RabbitMQ为典型的路由逻辑提供了多种内置交换机类型。若是你有更复杂的路由需求,能够将这些交换机组合起来使用,你甚至能够实现本身的交换机类型,而且当作RabbitMQ的插件来使用;
消息集群:在相同局域网中的多个RabbitMQ服务器能够聚合在一块儿,做为一个独立的逻辑代理来使用;
队列高可用:队列能够在集群中的机器上进行镜像,以确保在硬件问题下还保证消息安全;
多种协议的支持:支持多种消息队列协议;
服务器端用Erlang语言编写,支持只要是你能想到的全部编程语言;
管理界面: RabbitMQ有一个易用的用户界面,使得用户能够监控和管理消息Broker的许多方面;
跟踪机制:若是消息异常,RabbitMQ提供消息跟踪机制,使用者能够找出发生了什么;
插件机制:提供了许多插件,来从多方面进行扩展,也能够编写本身的插件;
使用RabbitMQ须要:ErLang语言包RabbitMQ安装包
RabbitMQ能够运行在Erlang语言所支持的平台之上:Solaris BSD 、Linux、 MacOSX 、TRU64 、Windows NT/2000/XP/Vista/Windows 7/Windows 八、
Windows Server 2003/2008/20十二、Windows 95, 9八、VxWorks
优势:
一、因为erlang语言的特性,mq 性能较好,高并发;
二、健壮、稳定、易用、跨平台、支持多种语言、文档齐全;
三、有消息确认机制和持久化机制,可靠性高;
四、高度可定制的路由;管理界面较丰富,在互联网公司也有较大规模的应用;
五、社区活跃度高;
缺点:
一、尽管结合erlang语言自己的并发优点,性能较好,可是不利于作二次开发和维护;
二、实现了代理架构,意味着消息在发送到客户端以前能够在中央节点上排队。此特性使得RabbitMQ易于使用和部署,可是使得其运行速度较慢,由于中央节点增长了延迟,消息封装后也比较大;
三、须要学习比较复杂的接口和协议,学习和维护成本较高;
参考连接地址:
RabbitMQ主页 https://www.rabbitmq.com/
RabbitMQ学习教程 https://www.rabbitmq.com/getstarted.html
专栏:RabbitMQ从入门到精通 http://blog.csdn.net/column/details/rabbitmq.html
RabbitMQ能为你作些什么 http://rabbitmq.mr-ping.com/description.html
RabbitMQ指南(1)-特性及功能 https://blog.zenfery.cc/archives/79.html
以上总结来自于连接地址:https://cloud.tencent.com/community/article/129032 因此仅供参考学习网络


园中RabbitMQ文章收集参考

固然这里博主就选取一些值得借鉴参考的博文来记录与备份,例如什么安装介绍基本使用集群经验总结一类的文章:
http://www.cnblogs.com/liqingwen/p/6412089.html [.NET] RabbitMQ 的行为艺术,此文介绍了RabbitMQ大体组织结构成分职责说明,以及环境搭建梳理和HelloWord、交换机的基本说明,居介绍性质多一些
http://www.cnblogs.com/sheng-jie/p/7192690.html RabbitMQ知多少 ,该文从基本介绍到环境搭建以及后续每一个功能点说明,文章排版阅读友好性强,居实践功能点多一些
http://www.cnblogs.com/zhangweizhong/category/855479.html RabbitMQ学习系列文,系列文从介绍到基本使用,以及后面的集群高阶使用,算是一个由浅入深的系列好文
http://www.cnblogs.com/wangiqngpei557/p/6158094.html RabbitMQ 高可用集群搭建及电商平台使用经验总结,从题目就能够看出是题主在实践项目中实战得出经验总结,想必是值得博主自己阅读学习的
http://www.cnblogs.com/dongkuo/p/6001791.html 消息队列——RabbitMQ学习笔记
http://www.cnblogs.com/panzi/p/6337568.html .NET操做RabbitMQ组件EasyNetQ使用中文简版文档
http://www.cnblogs.com/stulzq/p/7551819.html .NET Core 使用RabbitMQ
这里博主列出阅读过的此类文章,并非在说谁好谁坏,责在学习文中的写得好的地方顺便备份一下,对咱们理解开发有意义的地方是值得借鉴和学习的,同时咱们发如今文末留言中发现,园友在使用时存在多多少少量多问题,至此博主将会以身试法般的带着文档去实践,毕竟实践是检验理论的惟一标准.....架构


EasyNetQ文档跟进式学习与实践

这里可能有人要问了,为何不使用官方的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文档划重点与测试

这里是博主认为有必需要视为重点且须要实验验证的点,如若没有说起的地方,能够提出来一块儿讨论学习框架

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

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

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

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

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

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

测试代码以下:

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();
            });

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


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

三、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作了进一步的介绍和评比,再者这里也方便本身查阅收录一些当前园中的一些相关文章连接地址,再而后直接经过文档与在使用时比较关心的几个问题作了说明和可行性实验的研究,框架文档基本过了一两遍了,大体使用与集成博主大体心中有底,毕竟是在站人家的肩膀搞事情。固然就算是基于框架也能够有考虑的遗留项,因此咱们尽量了解RabbitMQ自身的一些原理和对原始Rabbit.Client API有必定了解确定是更加对集成有好处的.....

最后呐,可能此文前部分有些“敷衍”或者“老酒新装”之意,毕竟了解这瓶“老酒”确定是须要些时日才能品出味道的呐,可是博主以为就算是吧,也是对本身知识的多一层熟悉和铺垫吧,固然博主是打破砂锅问到底的那种,在问题上比较纠结,想弄清楚何为正确姿式!!因此上面的理解基本都是基于博主自己的思考与实验,可能略显不对,但凡请指出讨论,在此感激涕零,哈哈哈,最最后,若是文章对您或许有那么一丢丢的帮助,您的评论和点赞都是对博主很大的支持呐!!!O(∩_∩)O嗯!

相关文章
相关标签/搜索