1. 应用场景
适用于大存储量,顺序消息,广播和日志数据传输的场景。设计理念类似kafka,场景类似。和kafak的一些差异如下,可以考虑差异使用:
- 文本协议设计,透明。纯java实现,kafka是scala实现。
- 提供事务支持,包括本地事务和XA分布式事务。Kakfa不支持分布式事务
- 支持HA复制,包括异步复制和同步复制,保证消息的可靠性。Kafka也都支持。支持同步和异步刷盘,kakfa只支持异步
- 多种offset存储支持,Kafka是zookeeper。
- 需要大量的topic,kafka对多topic的性能影响比较大,而metaq相对较好。
- 实时性要求比较高。
- 消息局部有序,基于partition顺序消费。但如果consumer有多线程会出现乱序。
2. 产品特性
因为metaq主要实现和kafka原理相似,产品特性可以参考kafak,这里主要列出两个产品的差异点:
功能 | 特性 | Kafka | Metaq | 备注 |
数据可靠性 | 刷盘和复制 | 异步刷盘 同步异步复制 | 同同步异步复制步异步刷屏 |
|
性能对比 | 写入速度 | 100w/s | 7w/s | Kafka合并小数据批量发送 |
单机队列数 | 队列或分区数 | 5w/分区或队列 | 64/分区或队列 |
|
实时性 | 消息投递 | Kafka使用短轮询方式,实时性取决于轮询间隔时间。0.8版本以上已经支持长轮询 | 使用长轮询,同Push方式实时性一致 |
|
消费失败重试 |
| 支持固定时间重试,需要配置 | 支持定时重试,每次重试间隔时间顺延 |
|
定时/延时消息 |
| 不支持 | 支持 |
|
分布式事务 |
| 不支持 | 支持 |
|
消息查询 |
| 不支持 | 支持根据Message Id查询消息,也支持根据消息内容查询消息(发送消息时指定一个Message Key,任意字符串,例如指定为订单Id |
|
消息回溯 |
| Offset回溯 | 支持按照时间来回溯消息,精度毫秒 |
|
消费并行度 |
| 依赖与分区数 | 顺序模式:依赖分区数 乱序模式:取决与conusmer的线程数 |
|
消息轨迹 |
| 不支持 | 支持 |
|
Broker端消息过滤 |
| 不支持 | 基于tags过滤 支持上传代码过滤 |
|
消息堆积能力 |
| 更强 | 强 | 理论上都够用 |
3. 逻辑架构
![](https://i-blog.csdnimg.cn/blog_migrate/9f0e762d6c332310204fc09fe1ddfe83.png)
- 支持发布订阅模式
- 消息类型是message
4. 存储架构
![](https://i-blog.csdnimg.cn/blog_migrate/0e52a1aa614ba5c3cd2a9e596f410a48.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc0ea06ad32475a187b2577ea894e3c1.png)
- 消息持久存储
- metaq 将消息存储在本地文件中,每个文件最大大小为 1G,如果写入新的消息时,超过当前文件大 小,则会自动新建一个文件。文件名称为起始字节大小 。
- 即使一个 broker 为多个 topic 服务,这些 topic 的消息都存储同一个文件组中,消息顺序写入,永远 都是当前文件在写,其他文件只读
- broker 将消息存储到文件后,会将该消息在文件的物理位置,消息大小,消息类型封装成一个固定大 小的数据结构,暂且称这个数据结构为索引单元吧,大小固定为 16k,消息在物理文件的位置称为 offset。
- 多个索引单元组成了一个索引文件,索引文件默认固定大小为 20M,和消息文件一样,文件名是 起始字节位置,写满后,产生一个新的文件。
- 由于meta把kafka中一个partion一个文件夹的思路,转变成了多个partition共享一个文件,实现真正的顺序写。所以可以支持更多的topic和partition。
5. 处理流程
![](https://i-blog.csdnimg.cn/blog_migrate/4d41c37e09e682ba615fa4861ed66143.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3ac75da71ae86871f7205339a0d981d9.png)
- 处理数据流程:
- 根据 topic 和 partition 找到逻辑队列:A
- 根据 offset 从 A 定位指定的索引文件:B
- 从 B 中读取所有的索引数据:C
- 遍历 C,根据索引单元的消息物理地址和消息长度,找到物理消息 D,将 D 放入集合,并计 算消息的累加长度,若大于请求里消息最大长度 maxSize,则终止遍历,返回结果。
- 生产者的数据直接写入磁盘。(有可能在os的缓存中)。通过同步策略刷新进磁盘。
6. 分布架构
- 由于异步复制导致slave数据的可能缺失。写入必须通过master,读取可以slave。
- 也可以把slave升级为maste。当maste重启后变为salve。默认实现。
7. zookeeper架构
- ids
- /meta/brokers/ids/m1/master
- /meta/brokers/ids/m1/slaves1
- /meta/brokers/ids/m1/slaves2
- topics
- meta/brokers/topics/hello/m1-m
- /meta/brokers/topics/hello/m2-m
- /meta/brokers/topics/hello/s1-s
- /meta/brokers/topics/hello/s2-s
- partion数据存储在节点的数据中
- 分组信息存储
- /meta/consumers/hellogroup/ids/hellogroup_c1 节点数据为“hello1,hello2”
- /meta/consumers/hellogroup/ids/hellogroup_c2 节点数据为"hello2,hello3"
- 分组消费的位置存储
- /meta/consumers/hellogroup/offsets/t1/b1-1数据为 1 。
- /meta/consumers/hellogroup/offsets/t1/b1-2数据为 2 。
- /meta/consumers/hellogroup/offsets/t1/b2-1数据为 3 。
- /meta/consumers/hellogroup/offsets/t1/b2-2数据为 4 。
group 和 topic 是变量,以实际值为准。t,b分别为topic,broker,数字为位置。
8. 性能评估
Kafka单机写入TPS约在百万条/秒,消息大小10个字节。RocketMQ单机写入TPS单实例约7万条/秒,单机部署3个Broker,可以跑到最高12万条/秒,消息大小10个字节。Kafka的TPS跑到单机百万,主要是由于Producer端将多个小消息合并,批量发向Broker。
Metaq为什么没有进行合并发送:
- Producer通常使用Java语言,缓存过多消息,GC是个很严重的问题
- Producer调用发送消息接口,消息未发送到Broker,向业务返回成功,此时Producer宕机,会导致消息丢失,业务出错
- Producer通常为分布式系统,且每台机器都是多线程发送,我们认为线上的系统单个Producer每秒产生的数据量有限,不可能上万。
- 缓存的功能完全可以由上层业务完成。
Topic数的增加对RocketMQ无影响,长时间运行服务非常稳定。Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长。RocketMQ单机支持最高5万个队列,Load不会发生明显变化。
阿里云招聘,欢迎技术大牛加入:chris.yxd@alibaba-inc.com