这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
什么是消息队列
消息队列(Message Queue,MQ),指保存消息的一个队列,本质是个队列,但是支持高吞吐、高并发,并且高可用。消息队列是一个生产者-消费者模型,可以有效解决应用解耦、异步消息、流量削峰等问题。
业界常见的消息队列
- Kafka:分布式的、分区的、多副本的日志提交服务,在高吞吐场景下发挥较为出色
- RocktMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广
- Pulsar:是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、 采用存算分离的架构设计
- 字节BMQ:和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群
如何使用Kafka
graph TD
创建集群 --> 新增Topic --> 编写生产者逻辑 --> 编写消费者逻辑
基本概念
- Topic: 逻辑队列,不同Topic可以建立不同的partition
- Cluster: 物理集群,每个集群中可以建立多个不同的Topic
- Producer: 生产者,负责将业务消息发送到Topic中
- Consumer: 消费者,负责消费Topic中的消息
- ConsumerGroup: 消费者组,不同组Consumer消费进度互不干涉
- Offset: 消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增
- Replica: 每个分片有多个Replica(副本),Leader Replica将会从ISR(In-Sync Replicas)中选出
一条消息的流程
graph LR
Producer --生产--> Broker --消费--> Consumer
Kafka的特点
Producer采用了批量发送和数据压缩的方法来提高Kafka的吞吐量
Broker采用了顺序写、消息索引以及零拷贝的方法来提高性能。
对于一个Consumer Group,多个分片可以并发的消费,以此提高消费的效率。但需要解决 Consumer和Partition的分配问题,即对于每一个Partition来说,该由哪一个Consumer来消费。除了手动分配以外,Kafka采用了Rebalance的方法提供自动分配。简单来说,在Broker集群中,对于不同的Consumer Group来讲,都会选取一台Broker当作Coordinator,而它的作用就是帮助Consumer Group进行分片的分配。采取该方式后,即使Consumer Group中有发生宕机,或者有新的Consumer加入,Kafka会自动进行重新分配,达到稳定的消费状态。
问题
- 运维成本高
-
对于负载不均衡的场景,解决方案复杂
-
没有自己的缓存,完全依赖Page Cache
-
Controller和Coordinator和Broker在同一进程中,大量IO会造成其性能下降
为了解决这些问题,字节跳动自研的ByteMQ (BMQ)采取了一定的策略进行优化。
BMQ
ByteMQ(BMQ)是一个兼容Kafka协议,存算分离,云原生的消息队列。
运维操作对比
| 具体操作 | Kafka | BMQ |
|---|---|---|
| 重启 | 需要数据复制,分钟级重启 | 重启后可直接对外服务,秒级完成 |
| 替换 | 需要数据复制,分钟级替换,甚至天级别 | 替换后可直接对外服务,秒级完成 |
| 扩容 | 需要数据复制,分钟级扩容,甚至天级别 | 扩容后可直接对外服务,秒级完成 |
| 缩容 | 需要数据复制,分钟级缩容,甚至天级别 | 缩容后可直接对外服务,秒级完成 |
BMQ在重启、替换、扩容、缩容这些运维操作上的效率十分高,这得益于其架构的设计。实际上对于所有节点的变更操作,都仅仅只是集群元数据的变化,通常情况下都能秒级完成,而真正的数据存储在下层分布式文件存储系统中,因此才不需要考虑数据复制带来的时间成本。这与Kafka相比,是架构上的先进之处,也是云原生的体现。