这是我参与「第四届青训营 」 笔记创作活动的第12天
1. 消息队列概述
1.1 消息队列的应用场景
-
MQ 消息通道:发布(Publishes)订阅(Subscribes)模式
- 异步解耦:上游发布消息到消息队列中,下游无需关注上游的变化,只需订阅就行了
- 削峰填谷:下游出现故障时消息可以缓冲在队列中,可以等恢复之后再处理
- 发布订阅:扩展性非常强
- 高可用:大模块解耦成小模块
-
EventBridge 事件总线
- 事件源:将云服务、自定义应用、SaaS应用等应用程序产生的事件消息发布到事件集
- 事件集:存储接收到的事件消息,并根据事件规则将事件消息路由到事件目标
- 事件目标:消费事件消息
-
Data Platform 数据流平台
- 提供 流/批 数据处理能力
- 各类组件提供各类Connect
- 提供 Streaming/Function 能力
- 根据数据 schema 灵活进行数据预处理
1.2 主流的消息队列
| RabbitMQ | RocketMQ | Kafka | Pulsar | ||
|---|---|---|---|---|---|
| 推出时间 | 2007 | 2012 | 2010 | 2016 | |
| 使用语言 | Erlang | Java | Scala/Java | Java | |
| 单机吞吐量 | 一般 | 较高 | 高 | 高 | |
| 延迟 | 低 | 低 | 一般 | 低 | |
| 可用性(分片) | 高(主从架构) | 高(主从架构) | 非常高(分布式) | 非常高() | 分布式 |
| 一致性 | 较高 | 高 | 高 | 高 | |
| 扩展性 | 较高 | 高 | 高 | 非常高 |
2. Kafka详解
2.1 Kafka 简介
Kafka 是一种分布式的,基于发布 / 订阅的消息系统。主要设计目标如下:
- 以时间复杂度为 O(1) 的方式提供消息持久化能力,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能。
- 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒 100K 条以上消息的传输。
- 支持 Kafka Server 间的消息分区,及分布式消费,同时保证每个 Partition 内的消息顺序传输。
- 同时支持离线数据处理和实时数据处理。
- Scale out:支持在线水平扩展。
2.1.1 ZooKeeper
Kafka 存储数据:
- Broker Meta 信息(临时节点)
- Controller 信息(临时节点)
- Topic 信息(持久节点)
- Config 信息(持久节点)
-
选举机制
- Paxos 机制
-
提供一致性
- 写入(强一致性)
- 读取(会话一致性)
-
提供可用性
- 一半以上节点存活即可读写
-
提供功能
- watch 机制
- 持久/临时节点能力
2.1.2 Broker
- Broker 角色
- 若干个 Broker 节点组成 Kafka 集群
- Broker 作为消息的接收模块,使用 React 网络模型进行消息数据的接收
- Broker 作为消息的持久化模块,进行消息的副本复制以及持久化
- Broker 作为高可用模块,通过副本间的Failover 进行高可用保证
2.1.3 Controller 选举
- Controller 选举
- Broker 启动会尝试去 zk 中注册 controller 节点
- 注册上 controller 节点的 broker 即为 controller
- 其余 broker 会 watch controller 节点,节点出现异常则进行重新注册
2.1.4 Coordinator
- Coordinator 介绍
- 负责 topic-partition <-> consumer 的负载均衡
- 根据不同的场景提供不同的分配策略
- Dynamic Membership Protocol
- Static Membership Protocol
- Incremental Cooperative Rebalance
2.2 Kafka 高可用性
可用性定义
- Kafka 高可用
- 副本同步机制
- 提供 isr 副本复制机制,提供热备功能
- 写入端提供 ack=0,-1,1机制,控制副本同步强弱
- 副本切换机制
- 提供 clean/unclean 副本选举机制
- 副本同步机制
2.2.1 Kafka 副本选举
- Clean 选举
- 优先选取 lsr 中的副本作为 leader
- 如果 lsr 中无可用副本,则 partition 不可用
- Unclean 选举
- 优先选取 lsr 中的副本作为 leader
- 如果 lsr 中无可用副本,则选择其他存活副本
2.3 Kafka未来演进之路
去除zookeeper依赖
-
依赖Zookeeper存在问题
- 元数据存取困难:元数据的存取过于困难,每次重新选举的controller需要把整个集群的元数据重新restore,非常耗时而且影响集群的可用性
- 元数据更新网络开销大:整个元数据的更新操作也是以全量推的方式及逆行,网络开销也会非常大
- 强耦合违背软件设计原则:Zookeeper对于运维来说,维护zk也需要一定的开销,并且kafka强耦合与于zk也不好,还得时刻担心zk宕机的问题,违背软件设计的高内聚,低耦合的原则
- 网络分区复杂度高:zk本身并不能兼顾到broker与broker之间通信的状态,这就会导致网络分区的复杂度几何倍数增长
- 并发访问zk问题多
-
Kafka依赖KRaft
- Process.Roles = Broker:服务器在KRaft模式下只充当Broker进行数据存储
- Process.Roles = Controller:服务器在KRaft模式下充当Controller进行元数据的广播
- Process.Roles = Broker,Controller:服务器在KRaft模式下充当Broker和Controller
- Process.Roles = null:那么集群就假定是运行在Zookeeper模式下
总结
- 了解了消息队列的使用场景,知道常见的消息队列
- Kafka 详解
- Pulsar 详解