京东消息中间件JMQ

http://blog.csdn.net/javahongxi/article/details/54411464java

 

[京东技术]京东的MQ经历了JQ->AMQ->JMQ的发展,其中JQ的基于关系数据库,严格意义上讲称不上消息中间件,JMQ的存储是JFS和HBase,AMQ即ActiveMQ,本文说说JMQ。数据库

JMQ是京东自主研发的一款消息中间件系统,具备高可用、数据高可靠等特性。普遍应用于公司内部系统,包括订单、支付、库房等场景。缓存

总体结构服务器

  系统包括服务端、客户端、管理端与其余支撑模块。网络

  

  

       详细架构架构


                                                                      AMQ
 

                                                                       JMQ异步

 

       服务端分布式

  服务端提供了配置信息分发、重试消息管理和消息存储与分发这三大类功能。每一个服务端实例都具有这三类功能的服务能力,可是在实际部署上这三类功能对应三个不一样的集群,对应每个实例功能不叠加。在测试环境和库房等资源有限的环境下,这三类功能由同一个服务端实例提供服务。性能

  配置信息分发:负责客户端参数变动时与消息分配的服务端实例变动时通知客户端。测试

  重试消息管理:主要用于对业务系统临时处理不了的消息进行存放,而后再按照必定的策略投递给客户端处理。能够提供错误缘由、错误处理次数等查询。

  消息存储与分发:接收生产者投递的消息,把消息存放在本地磁盘上,消费者从该服务上拉取消息进行消费。

  

  客户端

  目前只提供了JAVA语言的SDK和支持HTTP协议的proxy,非JAVA语言经过proxy接入。

  管理端

  主要功能有:接入申请、消息元数据管理、重试消息信息查询、消息发送和消费日志查询、服务端状态信息管理查看、客户端链接信息管理查看等。

  支撑模块

  主要有报警模块、任务模块、归档模块、信息采集模块等。

  数据可靠性

  针对公司的业务特色,消息服务主要应用于订单、支付、物流等环节。服务端采用MASTER-SLAVE结构,消息在正常状况下会同时存放两份,其中一份会强制持久化到磁盘,磁盘作RAID-5。默认状况下客户端采用同步发送,每条消息到达服务端MASTER后会强制刷入磁盘同时并行推送一份到SLAVE上,SLAVE写入文件系统后不等待强制刷盘就反馈给MASTER。根据不一样的场景为了提升服务的可用性,普通级别的消息SLAVE断开后,该组服务能够正常使用,当SLAVE链接上后又会自动切换为保存两份。固然对数据可靠级别高的消息是强制要求数据必须写两份才算成功的。

  服务高可用

  每类消息通常都会分配3组及以上的服务组,每组服务包括一个MASTER和一个SLAVE,固然若是有须要也能够挂载多个SLAVE。

  客户端发送消息时,若是其中一组出现故障会重试发送给其余的组。

  虽然MASTER-SLAVE支持切换,提升服务的可用性,可是在实际生产中MASTER出现故障时会优先采用经过其余服务组自动接替生产服务的方式,本组服务只提供从SLAVE读取的方式,而不是让SLAVE接替MASTER的写入,避免临界状态下丢失消息。

  对要求严格顺序的消息,不能经过简单的切换服务组实现,具体实现方式参考《高可用保证消息绝对顺序消费的BROKER设计方案》(http://wely.iteye.com/blog/2347823)。

  消费模型

  因为公司之前有使用基于ACTIVEMQ二次开发的服务,服务端会存放客户端的消费位置,所以在自主研发JMQ时也延续了这种方式(能够兼容ACTIVEMQ的客户端)。可是ACTIVEMQ生产和消费都会操做索引文件,影响性能,JMQ吸收了这个经验教训。消费者在消费时按照索引分区顺序的消费,消费确认时只须要变动最后确认位置的值,不须要操做索引文件,并且多个消费者共用一个索引文件,各自保存本身的消费偏移位置就能够了。

  固然在实践过程当中,因为一些特殊场景须要,会容许必定范围内不彻底按照顺序消费,可是服务端会记录已经消费的索引区间。

  

与KAFKA的对比

  JMQ在服务端存储设计上与KAFKA有一些类似的地方,借鉴了文件按照偏移位置管理、顺序追加等特色。不过JMQ的存储和消费模型有本身的特色:

  消息存放

  JMQ每一个存储系统只有一个分段存储的日志文件,不一样类的消息按照服务端接收的顺序存放在日志文件中,经过索引程序按照不一样的消息(主题)分类名异步建立各自的索引,方便消费端获取消息时快速定位该客户端所关心的(主题)分类消息。每一个(主题)分类的索引划分了多个分区,同一(主题)分类的消息分配在多组服务器上的分区数是相同的。每一个索引分区都是以链表按照时间序存放消息引用信息。

  消费

  JMQ也采用客户端主动拉取的方式,可是客户端不须要协调本身应该从哪一个服务器上获取消息,服务端会控制好每一个索引分区里对应的消息在同一时刻只会被一个客户端线程取走,直到客户端反馈消费成功或者消费异常,消费异常会被重试程序转移到重试服务中。若是客户端长时间没有反馈信息,达到了超时时间,那么锁定的消息能够被其余的线程拉取走。

  因为服务端储存了每一个消费者消费的位置,所以服务器能够随时把已经消费的消息移除走。

主要特性与场景

  发布与订阅

  目前公司接入的消息绝大部分都采用这种方式,不一样类的消息经过主题名进行区分,多个消费者分组之间各自消费一份完整的消息内容,他们看到的消费视图如出一辙,惟一的区别就是各自消费进度不一样。

  同一个消费分组内的消费实例只会消费到其中一部分消息,各自链接服务端,经过抢占的方式进行消费。

  场景:

  以订单消息为例,订单系统在订单的生命周期里的每一次变动都会发送消息,订单查询系统、结算系统、库房生产系统等都会订阅该类型的消息,每一个系统拿到一份完整的消息,各自进行处理。

  广播

  因为发布订阅型的主题消息,若是要获取一份完整的消息就须要命名一个消费组,若是一类消息每一个消费者实例都须要获取一份完整的消息,若是还按照主题消息管理那么就须要为每个实例命名一个惟一的标识,使用时很是不方便,这时可使用广播类型的消息,每一个消费广播消息的实例都会拿到一份完整消息。

  场景:

  分布式数据库接入层对应的服务端拓扑信息须要调整,客户端能够订阅一个拓扑变动的广播消息,提早把须要变动的拓扑信息下发给每一个客户端备用,当捕捉到拓扑变动的异常后就启用备用拓扑信息。

  顺序消费

  消息的消费会根据服务端接收到的顺序,依次推送给客户端消费,消息若是乱序可能会引发最终结果不正常。

  场景:

  数据库binglog日志基于消息系统进行复制,接收到消息的客户端能够更新ElasticSearch中的索引信息,能够修改Redis中的值,同时也能够基于日志重放同步数据到一个全量的数据库中。若是有一条记录的更新和删除操做乱序到达消费端,那么各个系统的状态将会不一致。

  索引分区并行消费

  默认状况下,每一个索引分区的消息只可以按照顺序依次进行消费,若是索引分区内有一条消息处理比较慢,就会阻塞后面消息的处理,致使消息积压,影响消息的实时性。为了解决这个问题,能够增大索引分区数,可是每一个索引分区对应独立的文件夹,增大会致使文件夹数目扩大,并且不能根本解决,只是必定程度缓解积压的消息数目。若是让单个索引分区内的消息能够并行的把不一样区间的消息发送给客户端处理,这样若是有某条消息处理慢,服务端能够把后面的消息交给空闲的客户端线程去处理,当连续多个区间的消息都消费后再统一合并为一个大的消费区间,减小服务端须要记录的已消费区间数。

  场景:

  有一个经过消息派发任务的应用,每一个任务执行时间长短不一,消费端获取到消息后,根据消息构建任务执行,任务完成后反馈给服务端消费成功。因为任务执行时间长短不同,所以客户端的超时时间只能以最长的时间为参考进行设置,避免任务在执行过程当中因为超时被其余线程重复处理。可是当一个时间相对长的任务在执行时,它会占用该消息所在索引分区被锁定,后面的任务不能及时派发给空闲的客户端处理。这时服务端若是启用索引分区并行消费的特性,就能够及时的把后面的任务派发给其余的客户端去执行,同时也不须要调整索引的分区数。

  事务消息

  事务消息具备回滚的特色,当消息发送给服务端未提交前,若是关联的其余业务操做失败,客户端能够主动发起回滚,当回滚或者提交事务消息时网络故障,消息系统会主动调用客户端的事务状态查询接口,根据客户端查询到的事务状态决定消息是否提交或回滚。这样就可以保证消息系统和业务系统数据状态最终彻底一致。利用消息系统会主动查询不肯定状态消息的特色,能够作为多个资源的事务协调器使用。

  场景:

  变动缺货商品的库存信息时,须要更新下单系统中的库存数,须要通知搜索系统修改商品索引,须要通知网页缓存系统刷新。各个系统之间因为各类网络或服务等缘由形成状态不一致。可能出现库存变动了,其余系统的商品可销售状态没有修改正确,或者出现库存数据修改失败,可是其余系统的商品状态发生了变动。只能经过一些核对系统按期的把各个系统中的不一致状态变动为一致,加大了开发工做量,并且按期扫描可能引起性能问题。

  经过事务消息,能够很好的解决这类场景,不会由于网络不可用等缘由出现系统之间状态不一致。

  当更新任何一个服务出现故障时就抛出异常,事务消息不会被提交或回滚,消息服务器会回调发送端的事务查询接口,肯定事务状态,发送端程序能够根据消息的内容对未作完的任务从新执行,而后告诉消息服务器该事务的状态。

  

  做者介绍

  丁俊,有10年工做经验,目前就任于京东商城云平台,为消息中间件研发小组leader,主要负责公司内部高性能、高可用消息中间件的架构。

相关文章
相关标签/搜索