`
IXHONG
  • 浏览: 449384 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

京东消息中间件的演进

阅读更多

[京东技术]转载务必声明

 

本文转载自IPD-Chat,IPD-Chat为京东商城基础平台部门官方公众号,扫一扫二维码进行关注。

  本文将简单介绍下京东消息中间件的演进历程。以及作为消息中间件在每一代产品中我们是如何解决MQ面临的一些通用问题,比如:如何处理IO,消息如何存储,消息如何路由等等。

  我们在开始之前要明确一些基本概念:

Broker:消息中间件服务端的一个实例;

Producer:消息的发送方;

Consumer:消息的接收方;

Topic:消息中间里的数据分类的标示,一个topic也就代表一类消息,producer和consumer通过Topic实现关联。

  第一代JMQ

  2012年初,京东唯一一个类似消息中间件的产品还是一个基于数据开发的,消息分发系统。所以确切的说当时京东还没有一个统一的消息中间件平台,随着公司组织架构的升级,建设一个统一的消息中间件平台就提上了日程。

  目标就是建立一消息平台对外提供高可用,可扩展的消息传递服务。并能消息进行有效的治理。

  第一代选型

消息核心:基于ActiveMQ5.6做扩展。

配置中心:MySQL + ZooKeeper。

管理监控平台:自主研发。提供比ActiveMQ自带的管理平台更丰富的消息监控功能,并提供消息管理服务

  当时选择ActiveMQ是由于它是由JAVA开发符合公司的技术路线(.NET转JAVA),有主从复制方案,性能尚可(单实例TPS 3000+),支持JMS、AMQP等多种技术规范。至于为何选择zookeeper,可参考我厂另一篇文章《服务框架技术选型实践》的“注册中心选型”。

  AMQ是如何解决MQ面临的一些通用问题:

  因为核心是使用的ActiveMQ,所以部分问题就回归到了ActiveMQ是如何解决这些通用问题上来,但其中不乏我们对ActiveMQ的扩展,关于ActiveMQ部分的详细情况我们可以参看其官方文档,以下我们主要看下我们在其基础上的扩展及改进:

  1. 如何存储?

  ActiveMQ使用了KahaDB存储引擎进行存储,BTree索引,为了保证可靠性索引文件和日志文件都要同步刷盘。此外ActiveMQ通过虚拟主题(VirtualTopic)的方式实现Topic,也就是如果一个Topic有多个订阅者,ActiveMQ就为每个订阅者创建一个队列,那么producer每发一条消息,有多少个订阅者,broker就会将消息复制多少份,将其放到不同订阅者的队列中,broker在从中获取消息推送给consumer。

  2. 如何支持集群?

  当时的原生的ActiveMQ客户端在收发消息上是这样的:针对一个Topic发送者就只能往特定的单个Broker上发送消息,消费者亦是如此,只能从指定的单个Broker上消费消息。从客户端的角度来看就是不支持服务集群化,一旦分给这个Topic的这组Broker挂掉那针对这个Topic来说整个服务就处于不可用状态。

  我们做的第一件事就是让客户端支持集群,我们采用ZK作为配置中心对客户端进行了扩展,使客户端支持了集群的同时还实现了其对服务端动态扩展的支持。以下是集群化之后的客户端与服务端整体架构。

  客户端服务端整体架构

  

 

  3. push or pull?消息如何路由?

  AMQ采用的是push模式,也就是消息由producer发送到broker端之后是由broker推送给consumer。

  对于原生的客户端只能在单个Broker上收发消息,那也就不存在消息路由的问题,我们来看下集群化之后消息是如何路由的,这里的路由涉及到两个方面,一方面是producer在发消息是如何选择将消息发往哪个Broker,另一方面就是broker如何决定一条消息应该推送给哪个consumer。

  发送路由:1.随机发送,这种模式是完全随机的,也就是producer在topic指定的多个broker当中随机选择一个broker向其发消息。 2.加权随机发送,这种方式下我们可以对一个topic分配的多个broker设置不同的权重,发送时producer就根据权重来进行选择,权重越高被选中的几率越大。这种方式有个好处就是当一个broker有异常时我们就可以将其权重置为0,这样producer就不会往上发消息,待其恢复之后我们再逐步的将权重给予恢复,这就能够避免在单个broker出异常时客户端大量报错。

  消费路由:broker随机选择一个当前在线的consumer并将消息推送给它。

  客户端路由模型

  

 

  4.如何处理消费失败的消息?

  原生ActiveMQ的consumer在成功处理一条消息之后会向broker发一个ACK,以确认消息被成功消费。当处理一条消息失败之后就会向broker返回一个消息处理失败的应答,此时当broker收到这条处理失败的应答时会将这条处理失败的消息放到“死信队列”(DLQ)。针对每个普通队列Broker端都对应着这样一个死信队列,此队列的消息不能被消费者所获取。对此我们对客户端进行了扩展,在消费出错的时候拦截错误信息,然后将出错的消息通过SAF协议(我厂的SOA框架)调用“重试服务”将异常消息入库,入库成功之后consumer再向broker发送一个消费成功的ACK,这时Broker就会将此消息删除,这样我们实际上就是将broker端的消息转移到了库里。而后consumer再根据一定策略通过SAF去调用“重试服务”获取之前入库的消息进行处理。

  客户端重试架构图

  

 

  5.如何生成消息轨迹?

  原生ActiveMQ并不支持消息轨迹,我们扩展了服务端,对写消息和消费消息进行了拦截,在消息入队成功和消费成功后分别记下日志,再由Agent采集日志并进行归档,Agent将元信息写入归档库,然后将消息内容写入JFS(JD File System,我厂的分布式文件系统)。归档成功后可在管理控制平台追踪消息的处理轨迹,必要时还可下载消息体。

6.其他扩展、优化

优化了broker写消息逻辑将性能提升到单实例TPS 4000+(原生单实例TPS3000+);

实现了新的主从复制(原生主从复制为完全的同步复制,在slave落后时需要手动将Master数据拷贝到Slave,运维极其不方便)

实现新的主从选举使其更易维护,更好的支持集群(原生的主从选举容易出现双Master);

增加了监控告警模块以及其他的一些运维工具,使得管理里更加简单,运维更加方便。

  经过一系列的扩展 和优化,AMQ基本上实现了高可用、可扩展以及统一的治理消息等目标,初步形成了一套完整的企业级消息中间件解决方案。以下是AMQ平台粗略的整体架构图:

  AMQ整体架构

  

 

  第二代JMQ

  到2014年初AMQ几经优化已经很成熟。但随着公司业务的发展,接入主题数量越来越多,消息量也是成倍增长。此外随着公司在各地新建机房,应用的部署结构也变得比较复杂,这就有了跨机房部署等需求。加上AMQ本身的一些问题,归结一下主要有:

Broker较重,采用B-Tree索引,性能随消息积压量的上升急剧下降;

Broker端采用的VirtualTopic模式针对一个Topic有多个订阅者的情况会对每个订阅者单独存储一份消息。而京东的生产环境中大部分都是采用VirtualTopic并且每个Topic订阅者都很多,举个例子,比如“订单管道”消息:它有将近100个订阅者,也就是同一个数据要写将近100份,不仅如此,这100份消息还要通过网络发送到Slave上,经过这些流程,写入TPS只能达到几百。所以不管本地写性能性能、网落利用率、还是存储空间利用率来看这种方案都急需调整;

Broker逻辑复杂,其模型就决定了无法在其基础上扩展消息回放、顺序消息、广播消息等个性化需求,而实际使用过程当中又比较渴望我们支持此类特性;

重客户端,由于集群、异常消息重试等功能都是通过扩展ActiveMQ的原生客户端并引入SAF、ZooKeeper等服务得以支持的,一定程度上增加了客户端的复杂度,相应的在客户端的稳定性、可维护性等方面就打了折扣;

注册中心直接暴露给了客户端,这样最明显的一个缺点就是随着客户端实例数的增多,注册中心的连接数越来越多,这就很难对注册中心实施保护措施;

监控数据不完善。

  基于以上原因我们2014年初开启了第二代消息中间件JMQ的自研过程。主要做了以下一些工作:

JMQ服务端:实现轻量级的存储模型、支持消息回放、支持重试、支持消息轨迹、支持顺序消息、支持广播消息等,并兼容AMQ客户端使用的OpenWire协议;

JMQ客户端:实现轻量级客户端只和Broker通信,支持动态接收参数,内置性能采集、支持跨机房;

管理控制平台:管理监控功能更强大;

HTTP代理:基于Netty,支持跨语言。

  回到JMQ是如何解决MQ面临一些通用问题上来:

  1.如何解决IO问题?

  JMQ没有采用AMQ通过自己开发重复造轮子的方式解决IO问题,而是使用了Netty4.0,此框架开源,支持epoll,编程模型相对简单。这在一定程度上减少了服务端的开发工作,也降低了服务端的复杂度。

  在应用层,我们自定义了JMQ协议,序列化和反序列化也完全自己开发。这种序列化反序列化方式虽然在一定程度上降低我们的开发效率,但我们不用考虑如果采用第三方的序列化和反序列化方案会带来的性能损耗问题,对于性能上的提升是显而易见的。

  2.如何存储消息?

  JMQ存储分为日志文件(journal)和消息队列文件(queue)以及消费位置文件(offset)都存储在Broker所在机器的本地磁盘上。

  日志文件,主要存储消息内容,包括消息所在队列文件的位置,有以下特点:

同一broker上不同topic消息存储在同一日志文件上,日志文件按固定大小切分;

文件名为起始全局偏移量;

消息顺序追加;

日志文件同步刷盘。

  由于JMQ主要使用在可靠性要求极高的下单、支付等环节,所以broker必须保证收到的每条消息都落到物理磁盘,这样一种日志文件设计主要是为了提高多topic大并发下磁盘的写性能。不仅限于模型的设计,为了提高写性能我们在逻辑上还实现了Group Commit。下图是JMQ中Group Commit基本示意图:

  

 

  消息队列,主要存储消息所在日志文件的全局偏移量,此文件有以下特点:

同一broker上不同topic的队列信息存储在不同的队列文件上,队列文件按固定大小切分;

文件名为全局偏移量;

索引顺序追加;

队列文件异步刷盘。

  由于在日志的写入是单线程的,那我们在写入之前就可以提前获取到消息在队列文件的位置,并将这个位置写入到在日志文件当中。所以只要日志文件写成功,即便队列文件写失败,我们也能从日志文件中将队列恢复出来,因此队列文件采用异步刷盘。

  日志文件和队列文件模型

  

 

  消费位置文件:消费位置文件主要用于存储不同订阅者针对于某个topic所消费到的队列的一个偏移量。

  下图简单描述了消息在服务端的流转过程:

  

 

  3.如何容灾?

  说到容灾,我们上一节谈到了每条消息在broker上都会落地,但这远远不够,我们必须要保证单机失效甚至机房失效的情况下数据还能被恢复,所以我们需要的一套完整的方案来进行数据灾备。在AMQ里采用的是一主一从,主从分布在一个数据中心,主从同步复制这样的方案。

  JMQ里我们实现了一套全新的复制方案:采用一主一从,至少一个备份,主从分布在同一个数据中心、备份分布在其他数据中心,主从同步复制、备份异步复制这样一种方式进行数据灾备。主从同步复制这样就保证了同一条消息我们至少有两个完整备份,即便一个备份丢失,我们还有另一个备份可用。备份节点就保证了极端情况下即使整个数据中心挂掉,我们绝大部分的消息还能得以恢复;

  JMQ复制模型

  

 

  4.push or pull?消息如何路由?

  JMQ采用pull模式,也就是消息由producer发送到broker之后是由consumer主动发起请求去broker上取消息。

  发送者的路由和AMQ客户端采取的策略基本相同。

  消费者路由和AMQ差不多也是随机,不同点在于JMQ是拉模式,在Broker采取长轮询策略。

  5.如何处理消费失败的消息?

  与AMQ不同,由于JMQ 的broker直接就支持重试,在Consumer在处理消息失败时直接向服务端发送一个重试消息命令,服务端接到到命令后将此消息入库。随后在consumer发起拉取消息命令时,服务端再根据一定的策略从库里将消息取出,返回给consumer进行处理。这样做带来一个好处就是JMQ客户端减少了一个第三方服务依赖。

  6.如何记录消息轨迹?

  JMQ消息轨迹功能整体流程和AMQ基本相同,主要不同点在于JMQ将消息轨迹相关信息存储到HBase,这样JMQ消息轨迹信息的存储周期变的更长,可以存储的量也更大了,并且采用多种手段优化之后性能也得到了极大的提升。

  7.如何管理元数据?

  通过第一部分我们知道,AMQ的元数据会持久化在MySQL,并在入库的同时写入ZooKeeper,由ZK再下发到Broker和客户端。这样就有两个问题:

客户端引入了ZooKeeper这个第三方服务,引入服务越多那客户端稳定性和可维护性就越差。

注册中心也就是ZooKeeper直接暴露给了客户端,这样就会导致注册中心的连接数越来越多在出现故障时缺乏必要的手段对注册中心进行保护。

  在JMQ中我们依然利用MySQL来持久化元数据,同时也会将元数据写入ZooKeeper,ZooKeeper再通知到Broker,但客户端不再直接连接ZooKeeper,而是转而连接Broker,从Broker上获取元数据信息。由于每个Broker都有全量的元数据信息,所以客户端端连接任意的Broker都能获取到元数据信息。这种设计就带来了几个好处:

减少了客户端对ZooKeeper服务的依赖,至此我们客户端就只需和broker通信,客户逻辑得到了简化,客户端稳定得到了极大提升。

ZooKeeper不再暴露给客户端,这样ZooKeeper的稳定性也有了保证。

由于连接任意一个Broker都能获取到元数据,极端情况下即便有个别broker宕机也不影响客户端获取元数据,所以从另外一个角度来看这又提高了我们注册中心的可用性。

  8.其他

  除了以上提到的一些基本问题之外,我们还解决了很多问题,由于篇幅问题就不一一在此罗列说明,其中包括但不限于:

如何实现严格顺序消息;

如何实现广播消息;

如何实现两阶段事务;

如何实现消息回放。

  下面是JMQ的一个粗略整体架构图:

  

 

  JMQ性能数据

  测试所用机器情况:

  

 

  场景1:一主一从,Master同步刷盘+同步复制到Slave

  

 

  场景2:一主一从,Master异步刷盘+异步复制Slave

  

 

  JMQ规模

  Topic数量:1000+

  接入应用数量:2500+

  单日消息入队数量:500亿+

  JMQ3.0

  到2016年中,JMQ经过两个大版本的迭代,目前线上运行的JMQ2.0版本已经非常稳定,性能也很优秀,有人可能会问,既然都挺好了你们是不是就没事干了?只需要运维好就行了。其实不然,随着业务的发展,服务端规模的扩充,如何构建一个多样化、自动化的系统就显得尤为重要,所以在今年下半年我们又规划了我们JMQ3.0,JMQ3.0我们有几个重要的目标:

优化JMQ协议;

优化复制模型;

实现KAFKA协议兼容;

实现全局负载均衡;

实现全新的选举方案;

实现资源的弹性调度。

  从这些目标不难看出JMQ3.0在功能上和架构上都会有一个大的升级,所以我们打算通过两次大的迭代逐步实现上述这些目标。目前我们正在进行JMQ3.0第一版联调测试工作,预计在12月底第一个版本就会进行预发。

  第一版我们基本实现了Kafka协议兼容、类Raft的主从选举、全局负载均衡、对复制进行了优化,同时实现了一个弹性调度的简单DEMO。从我们目前的一些测试数据来看,新版本在性能上又有了一定的提高。期望JMQ3.0第一期上线后我们再通过一期或者两期的迭代,能够让JMQ更上一层楼。

  下图是我们JMQ3.0的一个整体架构:

  

 

  =============相关阅读=============

  服务化框架技术选型与京东JSF解密

  京东JIMDB建设之路

  本文转载自IPD,IPD-Chat为京东商城基础平台部门官方公众号。

  基础平台部门包括数据库、容器集群、中间件、图片存储、应用架构、机器学习、系统保障等技术方向。运营多个数据中心数万台服务器,支撑京东无数在线任务。IPD-Chat公众号会对基础平台目前的技术实践方案、最新项目动态等进行分享,纯技术干货,共同寻求突破~欢迎大家多多关注、共同交流!

  • 大小: 28.9 KB
  • 大小: 15.9 KB
  • 大小: 23 KB
  • 大小: 33.2 KB
  • 大小: 25.5 KB
  • 大小: 39.5 KB
  • 大小: 23 KB
  • 大小: 45.1 KB
  • 大小: 30.8 KB
  • 大小: 19.4 KB
  • 大小: 2.5 KB
  • 大小: 2.5 KB
  • 大小: 23.8 KB
0
0
分享到:
评论

相关推荐

    京东弹性数据库中间件-JED.pdf

    这表明了京东在数据库中间件技术演进的过程中,逐步从支持单一数据库系统发展到一个更加综合和先进的中间件解决方案。 功能特性部分强调了JED能够解决数据库管理和使用中的多个关键问题,主要包括: 1. 动态伸缩:...

    规模驱动技术:京东基础云服务演进

    综上所述,京东基础云服务的演进涉及了弹性计算、数据存储、内容分发、中间件等多个方面的技术进步。通过自主研发的核心系统和持续的技术创新,京东云为集团内外的业务提供了稳定、高效、可扩展的云服务支撑。随着...

    京东核心技术详解 www.toutiao.im

    京东是中国知名的大型电子商务公司,其核心技术涵盖了众多领域,包括但不限于服务化框架、云缓存、消息中间件以及整体技术架构等。本文将对京东的核心技术进行详细解析。 首先,服务化框架是支撑京东业务快速发展的...

    架构演进:京东应用架构设计.zip

    7. **消息队列**:通过引入RabbitMQ或Kafka等消息中间件,京东可以实现异步处理,解耦系统,提高系统吞吐量。 8. **容器化与Docker**:为了提升部署效率和资源利用率,京东可能采用了Docker进行容器化部署,配合...

    京东基础架构建设之路 全彩,京东商城基础架构部 有目录

    《京东基础架构建设之路》全书详尽地探讨了京东商城在基础架构层面的技术实践与演进,旨在为读者揭示大型电商平台如何通过先进的技术手段来支撑业务的发展和扩展。本书内容丰富,涵盖了多个关键领域,如容器集群技术...

    京东青龙系统数据库架构演进.pdf

    《京东青龙系统数据库架构演进》是一份详细介绍京东青龙系统从传统架构到云架构转变过程的技术文档。青龙系统作为京东的核心物流系统,涵盖了7个智能物流中心,运营着254个大型仓库,仓储面积达到550万平方米,并...

    京东架构演进.pptx

    "京东架构演进" 在本文中,我们将对京东架构演进的知识点进行详细的讲解,从单体架构到微服务架构的演进过程中,京东架构演进了十三代,每一代都解决了之前架构中存在的问题,并逐步完善了架构设计。 第一代架构:...

    京东广告计费架构演进之路-SACC2021年中国系统架构师大会.pdf

    在介绍京东广告计费系统架构演进的过程中,涉及到了一系列关键概念和知识点,下面将详细介绍。 一、京东广告计费系统架构演进背景 系统本质: 京东广告计费系统是一个典型的IO密集型计算任务系统,对数据一致性和...

    京东物流大数据应用.pptx

    1. **云计算技术**:京东利用JSHOP、JBOX、JCloud-CAP等中间件服务,构建了强大的云计算基础设施。JMQ提供了消息队列服务,JimDB为分布式数据库,Kubernetes则用于容器编排,实现资源的有效管理和调度。 2. **物流...

    2018-SACC-分布式存储与中间件设计

    2018-SACC大会-分布式存储与中间件设计 1. 汪黎_滴滴对象存储系统的架构演进实践.pdf 2. 丁俊 - 京东KV存储产品演进.pdf 3. 郭斯杰_从文件存储,对象存储到流存储 - 重新思考流计算时代的分布式存储.pdf

    第6章 分布式服务调用中间件.docx

    【分布式服务调用中间件】是现代互联网架构中不可或缺的一部分,它允许应用程序在不同的网络节点之间进行高效的服务调用,仿佛这些服务在...随着技术的不断发展,这些中间件将继续演进,以适应不断变化的互联网需求。

    京东云数据库架构实践.pptx

    通过中间件开发平台和PAAS服务,京东云还提供了数据库测试平台和发布平台,方便开发者进行应用开发和测试。 京东云数据库架构的实践,不仅展示了其在高性能、高可用性、弹性扩展和安全防护方面的卓越能力,而且强调...

    [详细完整版]京东的物联网.pdf

    京东的JoyLink是其物联网平台的一个组成部分,涵盖了设备连接、绑定、本地控制、消息触发和智能分析等功能。通过开源的方式,如SDK,JoyLink提供了API和调试工具,促进了产品移植和开发。此外,文章还提到了其他如...

    12份大数据技术演讲PPT资料.rar

    大数据产品进阶之道》、《新浪微博-实时流计算平台及应用模式》、《PingCAP-A TiDB Story》、《知乎-知乎容器平台演进及与大数据融合实践》、《Tron-隐私与系统架构》、《京东-商品数据的大规模数据计算和底层架构...

    京东私有云建设:挑战与应对之道

    3月31日,在华为ICT巡展北京站的活动中,刘海锋分享了《京东基础云服务技术演进》。基础云服务支撑着京东很多业务的发展。它可以分为三个层次,包括底层的存储服务,核心的中间件以及上层的弹性计算云,通过API以...

    支撑亿级运单的配运平台架构实践.pdf

    在应对亿级运单的挑战上,京东物流经历了数据存储和架构的不断演进。传统的Oracle和IBM AIX小型机方案逐渐被更先进的技术所取代,例如SQL Server和MySQL集群,以支持百万乃至千万级别的订单处理。随着时间的推移,...

    2018第十届中国系统架构师大会(SACC2018)幻灯片-10月17日

    │ │ 14:20 - 15:10 丁俊 - 京东KV存储产品演进.pdf │ │ 15:30 - 16:20 郭斯杰_从文件存储,对象存储到流存储 - 重新思考流计算时代的分布式存储.pdf │ │ ~$13:30 - 14:20 汪黎_滴滴对象存储系统的架构...

    java8看不到源码-jdonframework:领域驱动设计发布/订阅领域事件框架

    的消息中间件,您可以直接命令域模型做某事,并从域模型中监听任何域事件。 使用 JdonFramework,您可以构建具有异步并发性和更高吞吐量的领域驱动设计 + CQRS + EventSourcing 应用程序。 Jdonframework 帮你实现一...

Global site tag (gtag.js) - Google Analytics