Gleasy的分布式消息队列CloudMQ

声明
本文为Gleasy原创文章,转载请指明引自Gleasy团队博客

一。诞生背景
Gleasy子系统众多,子系统间的沟通也非常紧密(比如联系人系统,就需要向一说等提供底层数据),为降低系统复杂度,解耦势在必行;Gleasy的若干场景对性能要求很高,但对实时性要求不高,比如索引平台,消息中心,日志系统,每秒可能产生上万条甚至十几万条记录,直接操作DB无疑等于自残;Gleasy的一些基础信息,比如用户名的修改,往往需要及时地通知到多个子系统,便要求有一种广播机制来传达这些信息。解耦,高速缓冲,消息广播,所有这些正是消息队列(MQ)最为擅长解决的问题,因此使用MQ势成必然。

最初选用的是MQ是一个基于全PUSH模型的轻量级MQ Postman(借鉴于某互联网公司内部未开源,Postman为我们起的名字),基于MYSQL开发,使用quartz轮循推送,HTTP协议(JSON方式)传参。使用一段时间,发现问题极其严重,首先是延迟太厉害,由于使用轮循机制和HTTP协议,性能不高,轮循间隔也不敢配太短(通常都是配置为1-5S),很多场景下这种延迟完全接受不了(比如我们的实时索引平台);其次是不支持分布式,同一个主题(topic)订阅者太多时性能很差,加上使用MYSQL库表方式实现悲观锁,经常造成死锁;还有就是数据量问题了,使用MYSQL集中存储,当未消费的消息数量达到千万级别,整个系统开始变得极不稳定,再稍加并发压力,延迟就急剧上升。最终不得不放弃掉。

然后在开源世界苦苦筛选。ActiveMQ?不行,不支持分布式,TPS也1000左右,远达不到要求;ZeroMQ?太底层了,只是一个通信框架,放弃。然后在Apache的网站上看到了Kafka,一个开源的分布式消息队列,基于Zookeeper实现,性能超凡(TPS可达几万),支持分布式消费,消息顺序,海量数据,果断拿来实验,实验结果确实非常理想,美中不足是采用Scala语言开发,维护起来有些吃力,将来想改一改源码也较为困难;后来淘宝开源Meta系统(Kafka的JAVA版),拿过来对比,发现各方面能力都和Kafka持平,而且加入了一些集群和事务的能力,着实做了不少工作,根据官方公布的性能测试数据,大概可以达到2-4W的TPS,在Gleasy服务器上测试,也证实了这个结果。

虽然Meta系统在大部分情况下都能满足我们的需求,Gleasy最终还是选择了自主研发CloudMQ。原因很简单,MQ为最基础的中间件之一,影响全局。在弄清楚了Kalfa和Meta的原理之上,朝着我们关注的指标上狠狠努力,深度定制,实现自己完全可控的核心中间件,值得一做; 加上我们还有不少需求是Kalfa和Meta都无法满足(比如延迟消息)。这些因素共同促成了CloudMQ的诞生。

二。架构和原理
1. 软件架构
采用JAVA实现
基于Zookeeper和Redis

2. 逻辑架构
某个topic的多个生产者和同一个消费者(同一个ID的消费者称为同一个消费者,它们可分布部署多结点)逻辑架构图如下:

3. 物理架构

4. 工作原理
CloudMQ的工作原理和Kafka/Meta大体相似,都是采用分区机制。

每个topic都可以有多个分区;
topic的消息队列分散于各个分区的redis中;
生产者生产的消息会根据分区映射规则进入到某个分区中;
一个消费者会消费N个分区的消息;
一个分区同时只会被一个消费者的实例消费;
举例如下:
topic名称: topic1
消费者名称: consumer1
生产者结点数量:1
映射规则:根据消息ID对分区数量取模
消费者结点数量:从1 逐渐增加到 3
工作过程如下:
a. 生产者生产10条消息,ID分别为1至10.
b. 根据映射规则,这10条消息分别进入5个分区,其中1,6消息进入1号分区;2,7进入2号分区;3,8进入3号分区;4,9进入4号分区;5,10进入5号分区。
c. 消费者结点A启动,由于只有它一个结点,因此它负责所有分区即1到10号分区都由A消费
d. 消费者结点B启动,消费者A和B都检测到当前有2个结点在消费,于是根据规则进行分配。A结点负责1-5号分区,B结点负责6-10号分区。
e. 消费结点C启动,消费者A,B,C检测到当前有3个结点在消费,重新进行分配。A结点负责1,2,3,10号,B负责4,5,6号,C负责7,8,9号

online casino wp-image-358″ />

三。关键特性
支持订阅pub-sub和消息队列queue两种工作模式.
支持消息顺序(选用功能,可保证消费顺序和生产顺序完全一致)
消息分区生成和处理,同一分区严格保证顺序,不同分区可并发处理
支持消费者集群,从而实现任务分布式处理,且每个分区只被唯一一个结点处理
无BROKER设计,避免单点故障
队列数据分区分片存储,最佳工作状态下,消息数量可达数十亿级别.
支持延迟消息队列(区别于现有MQ的重要特性)
纯pull模式 通知机制,实际消息延迟小于10MS

四。性能指标
生产者,非延迟(tps 45000左右)
target/benchtest/bin/TestMqProducer /data/config/util/config_0_11.properties normal 500 50000
线程总时间:782889;平均:15.65778
实际总时间:1831; 平均:0.02662

生产者,批量生产(批量5-100条每次) (tps = 50000 相当给力)
target/benchtest/bin/TestMqProducer /data/config/util/config_0_11.properties mnormal 100 5000
线程总时间:477496;平均:1.761016124035582
实际总时间:6102; 平均:0.022504314986649357

生产者,延迟(14285 - 27777 / s)
全部都是非首次生成(tps = 27777)
[root@DB1 bin]# ./TestMqProducer /data/config/util/config_0_11.properties delay 500 50000
线程总时间:699032;平均:13.98064
实际总时间:1823; 平均:0.03646

全部都是首次生成 500线程 (tps = 14285)
[root@DB1 bin]# ./TestMqProducer /data/config/util/config_0_11.properties delay 500 50000
线程总时间:893383;平均:17.86766
实际总时间:3706; 平均:0.07412

消费者
50线程 消费50000条数据(tps = 35000 )
49499:t=2387:avg=0.03022319642821067 ms

结论:CloudMQ生产消息TPS可达4W以上,消费消息TPS达3.5W以上;延迟特性TPS近于1.4W至2.7W之间。

五。实战小结
CloudMQ上线1年,目前广泛应用于一盘,一说,消息中心,索引平台等关键业务系统,线上运行情况理想,完美实现预期目标。在性能和稳定性方面的表现也令人满意,扛得住严酷的使用环境。而且部署简单,无额外服务器部署成本,是Gleasy理想的消息中间件。

此条目发表在 Java技术, 分布式技术, 运维 分类目录。将固定链接加入收藏夹。

Gleasy的分布式消息队列CloudMQ》有 2 条评论

  1. Pingback 引用通告: Gleasy分布式架构体系介绍 | Gleasy团队博客

  2. Pingback 引用通告: 大型WEB应用性能调优总结 | Gleasy团队博客

发表评论