本文的主要内容包括以下几个方面:
滴滴的消息技术选型
为什么选择RocketMQ
如何构建自己的消息队列服务
RocketMQ扩展改造
RocketMQ使用经验
1. 滴滴的消息技术选型
1.1 消息历史
image-20181014102848377.png
如图,初期公司内部没有专门的团队维护消息队列服务,所以消息队列使用方式较多,主要以kafka为主,有业务直连的,也有通过独立的服务转发消息的。另外有一些团队也会用 RocketMQ、Redis的list,甚至会用比较非主流的beanstalkkd。导致的结果就是,比较混乱,无法维护,资源使用也很浪费。
1.2 弃用kafka
一个核心业务在使用kafka的时候,出现了集群数据写入抖动非常严重的情况,经常会有数据写失败。
主要有两点原因:
随着业务增长,topic的数据增多,集群负载增大,性能下降。
我们用的是kafka 0.8.2那个版本,有个bug,会导致副本重新复制,复制的时候有大量的读,我们存储盘用的又是机械盘,导致磁盘IO过大,影响写入。
所以我们决定做自己的消息队列服务。
![image-20181014113200764.png](https://upload-images.jianshu.io/upload_images/10425061-8d679ffbcd6af652.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
首先需要解决上面的解决业务方消息生产失败的问题。因为这个kafka用的是发布/订阅模式,一个topic的订阅方会有很多,涉及到的下游业务也就非常多,没办法一口气直接替换kafka,迁移到新的一个消息队列服务上。
所以我们当时的方案是加了一层代理,然后利用codis作为缓存,解决了kafka不定期写入失败的问题,如上图。
就是当后面的kafka出现不可写入的时候,我们就会先把数据写入到codis中,然后延时进行重试,直到写成功为止。
1.3 选择RocketMQ
经过一系列的调研和测试之后,我们决定采用RocketMQ。具体原因在后面会介绍。
为了支持多语言环境、解决一些迁移和某些业务的特殊需求,我们又在消费侧加上了一个代理服务。
然后形成了这么一个核心框架。业务端只跟代理层交互。中间的消息引擎,负责消息的核心存储。
在之前的基本框架之后,我们后面就主要围绕三个方向做。
一个是迁移。把之前提到的所有五花八门的队列环境,全部迁移到我们上面。这里面的迁移方案后面会跟大家介绍一下。
第二个就是功能迭代和成本性能上的优化。
最后一个重点就是服务化,业务直接通过平台界面来申请资源,申请到之后直接使用。
1.4 演进中的架构
image-20181014113633110.png
这张图是我们消息队列服务的一个比较新的现状。
先纵向看,上面是生产的客户端,包括了7种语言。然后是我们的生产代理服务。
在中间的是我们的消息存储层。目前主要的消息存储引擎是RocketMQ。然后还有一些在迁移过程中的Kafka。还有一个chronos,它是我们延迟消息的一个存储引擎。
再下面就是消费代理。
消费代理同样提供了多种语言的客户端。然后还支持多种协议的消息主动推送功能。包括HTTP 协议 RESTful方式。结合我们的groovy脚本功能,还能实现将消息直接转存到redis、hbase和hdfs上。更多的下游存储,我们都在陆续接入。
除了存储系统之外,我们还对接了实时计算平台,像Flink,Spark,Storm这些平台,我们也都提供了支持。
左边是我们的用户控制台和运维控制台。这个是我们服务化的重点。
用户在需要使用队列的时候,就通过界面申请topic,填写各种信息,包括身份信息,消息的峰值流量,消息大小,消息格式等等。
然后消费方,通过我们的界面,就可以申请消费。
运维控制台,主要负责我们集群的管理,自动化部署,流量调度,状态显示之类的功能。
最后所有运维和用户操作会影响线上的配置,都会通过zookeeper进行同步。
2. 为什么选择RocketMQ
因为从实际测试结果来看,RocketMQ的效果更好。
主要围绕两个测试进行。
2.1 测试-topic数量的支持
如下图所示,测试环境:
Kafka 0.8.2
RocketMQ 3.4.6
1.0 Gbps Network
16 threads
image-20181014114750847.png
这张图是Kafka和RocketMQ在不同topic数量下的吞吐测试。横坐标是每秒消息数,纵坐标是测试case。同时覆盖了有无消费,和不同消息体的场景。一共8组测试数据,每组数据分别在topic个数为16、32、64、128、256时获得的,每个topic包括8个partition。下面四组数据是发送消息大小为128字节的情况,上面四种是发送2k消息大小的情况。on 表示消息发送的时候,同时进行消息消费,off表示仅进行消息发送。
先看最上面一组数据,用的是kafka,开启消费,每条消息大小为2048字节。可以看到,随着topic数量增加,到256 topic之后,吞吐极具下。
可以先看最上面的一组结果,用的是Kafka,开启消费,每条消息是2kb(2048)。可以看到,随着topic数量增加,到256个topic之后,吞吐急剧下降。
第二组是是RocketMQ。可以看到,topic增大之后,影响非常小。
第三组和第四组,是上面两组关闭了消费的情况。结论基本类似,整体吞吐量会高那么一点点。
下面的四组跟上面的区别是使用了128字节的小消息体。可以看到,kafka吞吐受topic数量的影响特别明显。对比来看,虽然topic比较小的时候,RocketMQ吞吐较小,但是基本非常稳定,对于我们这种共享集群来说比较友好。
2.2 测试-延迟
Kafka
测试环境:
Kafka 0.8.2.2
topic=1/8/32
Ack=1/all,replica=3
测试结果:如下图
image-20181014153801681.png
(横坐标对应吞吐,纵坐标对应延迟时间)
上面的一组的3条线对应ack=3,需要3个备份都确认后才完成数据的写入。
下面的一组的3条线对应ack=1,有1个备份收到数据后就可以完成写入。
可以看到下面一组只需要主备份确认的写入,延迟明显较低。
每组的三条线之间主要是topic数量的区别,topic数量增加,延迟也增大了。
RocketMQ
测试环境:
RocketMQ 3.4.6
brokerRole=ASYNC/SYNC_MASTER, 2 Slave
flushDiskType=SYNC_FLUSH/ASYNC_FLUSH
测试结果:如下图
image-20181014153954985.png
上面两条是同步刷盘的情况,延迟相对比较高。下面的是异步刷盘。
橙色的线是同步主从,蓝色的线是异步主从。
然后可以看到在副本同步复制的情况下,即橙色的线,4w的tps之内都不超过1ms。用这条橙色的线和上面Kafka的图中的上面三条线横向比较来看,kafka超过1w tps 就超过1ms了。kafka的延迟明显更高。
3. 如何构建自己的消息队列服务
3.1 问题与挑战
challenge.png
面临的挑战(顺时针看):
客户端语言。需要支持PHP、GO、Java、C++。
只有3个开发人员。
决定用RocketMQ,但是没看过源码。
上线时间紧,线上的kafka还有问题。
可用性要求高。
使用RocketMQ时的两个问题:
客户端语言支持不全,它主要支持Java,而我们还需要支持PHP、Go、C++,RocketMQ目前提供的Go的sdk我们测的有一些问题。
功能特别多,如tag、property、消费过滤、RETRY topic、死信队列、延迟消费之类的功能,非常丰富。但是这个对我们稳定性维护来说,挑战非常大。
解决办法,如下图所示:
使用Thrift RPC框架来解决跨语言的问题。
简化调用接口。可以认为只有两个接口,send用来生产,pull用来消费。
主要策略就是坚持KISS原则(Keep it simple, stupid),保持简单,先解决最主要的问题,让消息能够流转起来。
然后我们把其他主要逻辑都放在了proxy这一层来做,比如限流、权限认证、消息过滤、格式转化之类的。这样,我们就能尽可能地简化客户端的实现逻辑,不需要把很多功能用各种语言都写一遍。
image-20181014164732619.png
3.2 迁移方案
架构确定后,接下来是我们的一个迁移过程。
image-20181014183257694.png
迁移这个事情,在pub-sub的消息模型下,会比较复杂。因为下游的数据消费方可能很多,上游的数据没法做到一刀切流量,这就会导致整个迁移的周期特别长。然后我们为了尽可能地减少业务迁移的负担,加快迁移的效率,我们在proxy层提供了双写和双读的功能。
双写:Procucer Proxy同时写RocketMQ和kafka。
双读:Consumer Proxy同时从RocketMQ和kafka消费数据。
有了这两个功能之后,我们就能提供以下两种迁移方案了。
3.2.1 双写
生产端双写,同时往kafka和rocketmq写同样的数据,保证两边在整个迁移过程中都有同样的全量数据。kafka和RocketMQ有相同的数据,这样下游的业务也就可以开始迁移。
如果消费端不关心丢数据,那么可以直接切换,切完直接更新消费进度。
如果需要保证消费必达,可以先在Consumer Proxy设置消费进度,消费客户端保证没有数据堆积后再去迁移,这样会有一些重复消息,一般客户端会保证消费处理的幂等。
生产端的双写其实也有两种方案:
客户端双写,如下图:
作者:qingfekg
链接:https://www.jianshu.com/p/1efeb2e79926
共同学习,写下你的评论
评论加载中...
作者其他优质文章