这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天
今日学习消息队列的原理与实战。主要针对零基础小白做的知识点梳理。
消息队列前世今生
消息队列(MQ)
指保存消息的一个容器,本质是个队列。但这个队列,需要支持高吞吐,高并发,并且高可用。
消息队列发展历程
- TIB
- IBM MQ/WebSphere
- MSMQ
- JMS
- AMQP/RabbitMQ
- Kafka
- RocketMQ
- Pulsar
常见消息队列对比
- Kafka: 分布式的、分区的、多副本的日志提交服务,在高吞吐场景下发挥较为出色;
- RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些实时场景中运用较广。
- Pulsar: 是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体、采用存算分离的架构设计
- BMQ: 和 Pulsar 架构类似存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的 Kafka 集群。
消息队列 kafka
从 kafka 使用场景,业务日志、用户行为数据、Metrics 数据展开,介绍一条消息从生产到消费的处理流程。
如何使用 Kafka
-
- 创建集群
首先需要创建一个Kafka集群。
-
- 新增 Topic
需要在这个集群中创建一个 Topic,并且设置好分片数量。
-
- 编写生产者逻辑
引入对应语言的 SDK,配置好集群和 Topic 等参数,初始化一个生产者,调用 Send 方法,将你的Hello World 发送出去。
-
- 编写消费者逻辑
引入对应语言的 SDK,配置好集群和 Topic 等参数,初始化一个消费者,调用 Poll 方法,你将收到你刚刚发送的 Hello World。
基本概念
- Topic:
逻辑队列,不同 Topic 可以建立不同的 Topic。
可以理解成每一个不同的业务场景就是一个不同的 topic,对于这个业务来说,所有的数据都存储在这个 topic。
- Cluster:
物理集群,每个集群中可以建立多个不同的 Topic。
每个集群中可以新建多个不同的topic。
- Producer:
生产者,即消息的生产端。负责将业务消息发送到 Topic 中。
- Consumer:
消费者,负责消费 Topic 中的消息。
消息的消费端,负责消费已经发送到topic中的消息。
- ConsumerGroup:
消费者组,不同组 Consumer 消费进度互不干涉
通常 topic 会有多个分片,不同分片之间的消息是可以并发来处理的,这样提高单个 Topic 的吞吐。
Offset
Offset: 消息在 partition 内的相对位置信息,可以理解为唯一 ID,在 partition 内部严格递增。
对于每一个 Partition 来说,每一条消息都有一个唯一的 Offset,消息在 Partition内的相对位置信息,并且严格递增。
Replica
每个分片有多个 Replica,Leader Replica 将会从 ISR 中选出。
Replica: 分片的副本,分布在不同的机器上,可用来容灾,Leader 对外服务,Fllower 异步去拉取 leader 的数据进行一个同步,如果 leader 挂掉了,可以将 Follower 提升成 leader 再对外进行服务
ISR(In-Sync-Replicas):意思是同步中的副本,对于 Follower 来说,始终和 leader 是有一定差距的,但当这个差距比较小的时候,我们就可以将这个 follower 副本加入到 ISR 中,不在 ISR 中的副本是不允许提升成 Leader 的。
数据复制
下图为 Kafka 副本的分布图。
图中,每个 Broker 代表每一个 Kafka 的节点,所有的 Broker 节点最终组成了一个集群。
即,图中整个集群,包含了 4 个 Broker 机器节点,集群有两个 Topic,分别是 Topic 1 和 Topic 2,Topic 1 有两个分片,Topic2 有 1 个分片,每个分片都是三副本的状态。
这里中间有一个 Broker 同时也扮演了 Controller 的角色,Controller 是整个集群的大脑,负责对副本和 Broker 进行分配。
数据复制问题
对于 Kafka 来说,每一个 Broker 上都有不同 topic 分区的不同副本,而每一个副本会将其数据存储到该 Kafka 节点上面。
对于不同的节点之间,通过副本直接的数据复制,来保证数据的最终一致性,与集群的高可用。
Kafka 架构
ZooKeeper:
负责存储集群元信息,包括分区分配信息、Controller 计算好的方案等。
从一条消息视角看Kafka为啥可以支撑如此高的吞吐
Producer—生产—Broker—消费—Consumer
- Producer: 批量发送、数据压缩;
- Broker:顺序写,消息索引,零拷贝;
- Consumer: Rebalance。
重启操作
如果我们对一个机器进行重启。
首先,我们会关闭一个 Broker ,此时如果该 Broker 上存在副本的 Leader,那么该副本将发生 Leader 切换,切换到其他节点上面并且在 ISR 中的 Follower 副本。
图中切换到了第二个 Broker 上面,而此时,因为数据在不断的写入,对于刚刚关闭重启的 Broker 来说,和新 Leader 之间一定会存在数据的滞后,此时这个 Broker 会追赶数据,重新加入到 ISR 当中当。
数据追赶完成之后,我们需要回切 leader,这一步叫做 prefer leader,这一步的目的是为了避免,在一个集群长期运行后,所有的leader都分布在少数节点上,导致数据的不均衡。
通过上面的一个流程分析,我们可以发现对于一个 Broker 的重启来说,需要进行数据复制,所以时间成本会比较大,比如一个节点重启需要 10 分钟,一个集群有 1000 个节点,如果该集群需要重启升级,则需要 10000 分钟,那差不多就是一个星期,这样的时间成本是非常大的。
但是可以不可以并发多台重启呀?
不可以。在一个两副本的集群中,重启了两台机器,对某一分片来进,可能两个分片都在这台机器上面,则会导致该集群处于不可用的状态。这是更不能接受的。
替换、扩容、缩容
- 替换,和重启有什么区别?
替换,本质上来讲,就是一个需要追更多数据的重启操作,因为正常重启只需要追一小部分,而替换,则是需要复制整个 leader 的数据,时间会更长
- 扩容
当分片分配到新的机器上以后,也是相当于要从 0 开始复制一些新的副本
- 缩容
缩容节点上面的分片也会分片到集群中剩余节点上面,分配过去的副本也会从 0 开始去复制数 据
替换、扩容、缩容三个操作均有数据复制所带来的时间成本问题,所以对于 Kafka 来说,运维操作所带来的时间成本不容忽视。
Kafka 问题总结
-
1. 运维成本高
- 因为有数据复制的问题,所以 Kafka 运维的时间成本和人力成本都不低。
-
2. 对于负载不均衡的场景,解决方案复杂
- 对于负载不均衡的场景,我们需要有一个较为复杂的解决方案进行数据迁移,从而来权衡 IO 升高的问题。
-
3. 没有自己的缓存,完全依赖 Page Cache
-
除了以上两个问题以外,Kafka 自身还存在其他的问题。
-
比如,Kafka 没有自己的缓存,在进行数据读取的时候,只有 Page Cache 可以用,所以不是很灵活
-
-
4. Controller 和 Coordinator 和 Broker 在同一进程中,大量 IO 会造成其性能下降
- Kafka 的 Controler 和 Coordinator 都是和 Broker 部署在一起的,Broker因为承载大量 IO 的原因,会导致 Controller 和 Coordinator 的性能下降,如果到一定程度,可能会影响整个集群的可用性。
拓展阅读: