浅谈对RabbitMQ的认识

一.什么是消息队列?何时使用它web


  在传统的web架构中(此处特指Java SSM架构),用户在web中进行了某项须要和后台产生交互的操做后,通常都要开启一个session,从view层开始,由controller层寻找相应的模型构件,找到相应的model后,生成相应的Java bean,再由Spring将bean映射到逻辑层,找到相关业务逻辑后,调用持久层框架,由数据库进行数据操做。能够看出,实际的业务逻辑十分复杂,在业务逻辑很少时尚可接受,但因为大多数数据库更新采用的是串行的方式,全部操做都须要在上一个操做完成后才能开始,就拿最多见的注册帐号操做来讲,常规操做下,用户输入基本信息之后,服务器响应时间咱们假设为50ms,验证验证码的正确也须要50ms,验证手机号或者邮箱一样须要50ms,那么加起来就须要150ms。能够看出,在数据库操做数量增大后,即便是一个很是简单的select操做,也须要产生不小的服务器负担,一旦业务量也同时增大,极可能会形成服务器卡顿甚至宕机,给用户带来极差的体验。而以前的解决方法,是使用cookie技术,即将数据存放到客户端的浏览器上,但cookie技术虽然简化了业务流程,随之而来的是安全性的下降。某些居心不良的用户可能会修改本地cookie,具备很大的安全隐患。(补充一句,也能够经过对SQL自己的优化,经过调整行级锁来达到最佳的锁粒性,具体能够参考《高性能mySQL》一书,本文不作赘述。)shell

  所以,咱们引入了消息中间件(Message-oriented middleware,MOM)技术。消息代理服务器经过将用户消息暂存到一个消息容器中,将一系列复杂的业务流程进行解耦,每一个模块只须要完成它对应的功能,不须要关心别的模块。画一张图以便你们理解。数据库

  能够看到,经过使用MOM技术,咱们将本来可能须要150ms的业务流程缩短到了只须要70ms(实际上优化的时间会更多,由于RabbitMQ的特点正是响应时间极短,达到了微秒级)。同时,实现了业务的解耦,验证手机号时不须要关心用户此时有没有经过验证码。固然,若是并发量太大,咱们能够在超过消息队列最大吞吐量后,选择抛弃用户请求,或者直接将用户重定向至报错页面。根据采用技术的不一样,最大吞吐量也有所不一样,本文介绍的RabbitMQ可达到万级,若是并发量大于万级,能够采用Kafka等技术。浏览器

  固然,一种技术不可能只有优势而没有缺点。我我的对MOM的理解是这样的,首先它确实对高并发场景有很大的帮助,好比双十一等访问量激增的时候,能够有效帮助服务器进行错峰。同时对各模块进行解耦,使系统各模块间的依赖度下降,不至于一个模块挂了整个系统所有瘫痪。最后,MOM是一种异步请求,无需服务器响应就能够发送下一个请求。可是,与之伴生的是,它对服务器压力的激增,和一系列的现实问题。我打个比方,就拿双十一抢购来讲,假如采用了MOM技术,用户下的订单被存在消息队列服务器上,此时,若是后台的库存临时出现变化了,好比某我的下了不少订单忽然退单了,因为数据还没有存入数据库,其可能会产生一些影响,又或者说在后续的某个部分, 好比你下了订单之后,后续的手机号填错了,此时你已经经过了下单模块,订单信息已经存入了消息队列服务器中,但后续本该异步的出现了错误,那可能就会出现脏读的状况。固然这些问题都是能够经过一 系列预案,用复杂的逻辑判断来规避的,但势必增长了系统出错的风险,由于系统的复杂性被大大地增长了。更须要注意的是,虽然系统各模块间的依赖度下降了,但这是创建在对消息队列服务器的依赖上的,若是消息队列服务器挂了呢?因此,每项技术都有其应用场景,咱们应该根据实际使用状况,来具体分析要不要使用MOM技术。安全

 

二.AMQ协议服务器


 

  RabbitMQ基于AMQP规范,AMQP规范不只定义了一种网络协议,也定义了服务器端的服务和行为。这就是高级消息队列(Advanced Message Queuing,AMQ)模型,其在逻辑上定义了三种抽象组件用于指定消息的路由行为:cookie

·交换器(Exchange),消息代理服务器中用于把消息路由到队列的组件。网络

·队列(Queue),用来存储消息的数据结构,位于硬盘或内存中。session

·绑定(Binding),一套规则,用于告诉交换器消息应该被存储到哪一个队列。数据结构

  一个AMQP能够有多个信道,容许服务器和客户端之间进行屡次通讯,这就是多路复用。须要注意的是,在尝试声明一个与现有队列同名的信道时,若是新队列的属性与现有队列不同,那么RabbitMQ将关闭RPC请求的信道。 要正确处理错误,你的客户端应用程序应该监听来自RabbitMQ的Channel.Close命令,以便可以正确响应。有的客户端可能会经过在Channel.Close命令注册一个回调方法来自动触发。

  低层AMQP帧是由五个不一样的组件构成的,其分别是:

 ·   帧类型
 ·   信道编号
 ·   以字节为单位的帧大小
 ·   帧有效载荷
 ·   结束字节标记(ASCII值206)
  低层AMQP帧的头部是三个字段,这三个字段组合起来被称为帧头。第一个字段是指示帧类型的单个字节,第二个字段指定帧的信道,第三个字段携带帧有效载荷的字节大小。
 
  在帧内部,位于头部以后和结束字节标记以前的内容就是帧的有效载荷。帧的设计是为了保护其携带内容的完整性。 
 
  AMQP的帧类型一样分为五种:协议头帧,方法帧,内容头帧,消息体帧,心跳帧。其中协议头帧用于链接到RabbitMQ,仅使用一次。方法帧携带发送给RabbitMQ或从RabbitMQ接收到的RPC请求或响应。内容头帧包含一条信息的大小和属性。消息体帧包含消息的内容。心跳帧在客户端与RabbitMQ之间进行传递,做为一种校验机制确保链接的两端均可用,且均在正常工做。 

三.RabbitMQ集群
  消息队列中间件技术是分布式系统中的重要组件,所以,咱们须要对RabbitMQ集群有必定的认识。维护集群所需的工做和开销与集群中节点的数量多少有关,通俗一点来讲,也就是越大的系统,就须要占用越多的额外资源对其进行管理,其遵循木桶原理,与集群中最慢的那个节点的响应速度有关。通常来讲,RabbitMQ集群至少须要两个节点,至多在32-64个之间,由于其系统的复杂度是非线性上升的,系统中的每个节点都须要了解其余节点的状况,这致使了你每添加一个新的节点,复杂性就会成指数化上升。不过,官方提供了一个工具,RabbitMQ UI,来解决这一问题,其能够很好地管理大型RabbitMQ集群。
  此外,向RabbitMQ添加的节点必须是磁盘节点或者内存节点。若是集群拥有大量的运行时状态时,相比内存节点,磁盘节点更容易收到磁盘I/O的影响。
内存节点仅将运行时状态信息存储在内存数据库中。能够说两种存储方式各有优劣,须要开发人员根据实际需求去进行判断。须要注意的是,集群里至少应当存在一个磁盘节点,由于一旦集群出现问题崩溃,崩溃的内存节点再次加入集群时,不会包含任何以前存储的信息,换而言之,这就是一个全新加入的节点,所以,须要磁盘节点将配置信息发送给它,若是有多个磁盘节点,那么应该把整个集群都关闭,再按照顺序重启节点,优先启动拥有最多正确状态的那个节点。
  有两种方式向集群中添加节点,其一是修改rabbitmq.cfg文件,来定义集群中的每一个节点。由于有不少自动配置管理工具,好比Chef,Puppet等,这种方式更简单且不容易出错。第二种方式是经过使用cmd或者shell命令行来添加节点,这种方法工做量大,且相对来讲不严格,但更有助于操做人员了解集群降级问题的排查,有兴趣的朋友能够自行了解一下erlang cookie及其对RabbitMQ集群的应用。
 
结束语
  本人的第一篇技术博客就暂时到此为止,本文仅涉及到原理和应用部分,但愿本身之后有空详细讲一下RabbitMQ如何实际开发(但愿懒癌之后每周都能更新一篇博客啦)另外有不正之处也望各位大神能多多指教,毕竟这是个人一家之言,其确定有不足之处。 本文系我原创,如需转载,请联系我本人,并注明出处,若有侵权,必追究其法律责任。
 
参考书目:
Gavin M.Roy.RabbitMQ in Depth[M],2018.6,21-24.
相关文章
相关标签/搜索