初识Kafka
Kafka官方网站将Apache Kafka表述为一种高性能、分布式的消息发布与订阅系统,同时也是一个强大的流式处理平台。它被设计用于处理实时数据流,能够以高吞吐量在系统组件之间可靠地传输数据。Kafka不仅允许生产者发布消息到多个主题上,还允许消费者订阅这些主题并进行消息地拉取,这一机制支持了数据的解耦、冗余存储及实时处理。
Kafka的核心优势在于其高度可拓展性、持久化特性和容错能力。通过在集群中分布式的部署多个代理(brokers),Kafka能够轻易地处理极高的数据吞吐量、每秒处理数百万条消息,同时保证低延迟。数据在Kafka中是以日志的形式存储的,这使得即使在系统出现故障时也能保证数据不丢失,实现了高可用性。
作为流处理平台,Kafka集成了Kafka Streams库,该库使得开发者能够构建轻量级的实时流处理应用,直接在Kafka内部执行数据转换和聚合操作,无需依赖外部复杂系统。此外,Kafka与许多流行的流处理框架如Apache Spark、Flink等紧密集成,进一步丰富了其在大数据处理和分析领域的应用范围。
总而言之,Kafka不仅仅是一个消息队列,而是一个全面的分布式流式处理生态系统,广泛应用于日志聚合、实时监控数据分析、事件驱动架构以及大规模数据管道构建等多个领域,为企业提供了一站式的解决方案来应对现代数据处理的挑战。它有3个主要功能:
Kafka包含用于与其他系统发生交互的客户端。其中的一个客户端叫做生产者,它向Kafka Broker发送数据流。Kafka的另一个客户端叫做消费者,它从Broker读取和处理数据。数据的目的地不一定只有一个。生产者和消费者之间是完全解耦的,它们是独立运行的。
Kafka的架构
从高层次来看,架构分为两层:
- 计算层
- 存储层
计算层
计算层允许各种应用程序通过API与Kafka Broker通信。
生产者使用生产者API。如果数据库等外部系统想与Kafka通信,它还提供Kafka Connect作为集成API。
消费者通过消费者API与Broker通信。我们可以使用 Kafka Connect API 将事件数据路由到其他数据处理平台上,例如搜索引擎或数据库。
我们可以在消费者中订阅主题,按照产品维度进行聚合。
存储层
这一层由Kafka Broker组成。Kafka Broker以集群模式运行。数据存储在不同主题的分区中。
主题就像一个数据库表,主题中的分区可以分布在不同的集群节点上。在分区内,事件严格按照偏移量(offset)排序。偏移量代表事件在分区中的位置,并单调递增。
在Broker上持久化的事件是不可变的、只可追加的,即使是删除也被模拟为删除事件,而不是直接从磁盘上删除数据。因此,生产者只能处理顺序写入,消费者只能顺序读取。
Kafka Broker的职责包括管理分区、处理读写操作以及管理分区的数据复制。它的设计非常简单,因此易于拓展。
由于Kafka Broker是以集群模式部署的因此有两个必要的组件来管理节点:控制面板和数据面板。
控制面板
控制平面管理Kafka集群的元数据。以前的版本中是由Zookeeper来管理控制器:挑选一个Broker作为控制器(Controller)。现在,Kafka使用名为KRaft的共识模块来实现控制面板,选取几个Broker做为控制器。
ZooKeeper模式
Kafka的控制平面是通过一个名为Zookeeper的外部共识服务来管理的。其中一个代理被指定为控制器。控制器负责与ZooKeeper以及集群中的其他代理进行通信。集群的元数据持久化存储在ZooKeeper中。
以下是ZooKeeper为Kafka保存的一些主要元数据:
- 集群管理信息:包括集群中的所有broker信息,如它们的ID、地址、监听的端口以及它们的状态。
- 主题和分区信息:包括所有主题的列表、每个主题的分区数、每个分区的副本分布情况、以及哪些副本是首领副本。
- 配置信息:Kafka集群的配置信息,包括各种主题的配置,如副本因子、保留策略等。
- 消费者信息:消费者组的元数据,包括消费者组的成员信息、每个消费者消费的分区信息以及消费偏移量。
- 选举和领导者信息:用于在broker之间进行领导者选举的元数据,以确保集群的可用性和数据的一致性。
- 访问控制列表(ACLs):存储了Kafka的访问控制列表,用于权限管理和安全控制。
- 动态配置:Kafka的动态配置变更也会存储在ZooKeeper中,这些配置可以在不重启服务的情况下动态更新。
Controller控制器
Kafka Controller是Apache Kafka集群中的关键组件,其主要作用是在集群的多个broker之间协调和管理操作。
- 领导者选举:在Kafka集群中,每个分区都有一个leader副本和若干个follower副本。Controller负责管理和协调这些副本之间的领导者选举过程。
- 管理分区和副本状态:当集群中的broker启动或关闭时,Controller负责管理分区的状态变更,以及相应副本的状态变更。
- 维护集群元数据:Controller负责维护集群的元数据信息,包括分区信息、副本位置信息等。
- 处理分区重分配:当执行分区重分配操作时,Controller负责协调和管理分区副本在broker之间的移动。
- 处理broker故障:当某个broker发生故障时,Controller负责检测到这一情况,并触发新的领导者选举过程,确保故障broker上的分区可以快速恢复。
- 管理新创建的主题:当在Kafka集群中创建新主题时,Controller负责分配分区副本到各个broker,并初始化相关元数据。
- 处理集群扩展和收缩:当集群需要增加或移除broker时,Controller负责管理相关的元数据和状态变化。
- 同步操作日志:Controller会将操作日志记录到内部主题(__consumer_offsets 或 __controller_epoch)中,确保集群状态的一致性和持久性。
Kafka Controller通过这些功能确保了Kafka集群的高可用性和稳定性,使得Kafka能够高效地处理大规模数据流。
KRaft模式
在KRaft中,一部分代理被指定为控制器,这些控制器提供了以前由ZooKeeper提供的共识服务。现在,所有的集群元数据都存储在Kafka主题中,并在内部进行管理。
KRaft集群节点角色
在KRaft模式下,Kafka集群可以以专用模式或共享模式运行。在专用模式下,一些节点的process.roles配置将设置为controller,其余节点将设置为broker。对于共享模式,一些节点的process.roles将设置为controller,broker,这些节点将承担双重责任。选择哪种模式取决于集群的规模。
KRaft模式控制器
在KRaft模式的集群中,充当控制器的代理列在每个代理上设置的controller.quorum.voters配置属性中。这使得所有代理都能够于控制器进行通信。其中一个控制器代理将成为活动控制器,它将负责与其他代理通信以处理元数据的更改。
所有控制器代理都维护一个内存中的元数据缓存,该缓存会保持更新,以便在需要时任何控制器都可以接管成为活动控制器。这是KRaft的一个特性,使其比基于ZooKeeper的控制平面高效的多。
KRaft集群元数据
KRaft基于Raft共识协议,该协议作为KIP - 500的一部分引入到Kafka中,其他相关的KIP中定义了更多详细信息。在KRaft模式下,反应所有控制器管理资源当前状态的集群元数据存储在一个名为__cluster_metadata的但分区Kafka主题中。KRaft使用这个主题在控制器和代理节点之间同步集群状态的更改。
活动控制器是这个内部元数据主题的单个分区的领导者。其他控制器是副本跟随者。代理是副本观察者。因此,控制器不是将元数据更改广播给其他控制器或代理,而是由它们各自去获取这些更改。这使得保持所有控制器和代理的同步非常高效,并且还缩短了代理和控制器的重启时间。
KRaft元数据复制
由于集群元数据存储在Kafka主题中,该数据的复制与我们在数据平面复制模块中非常相似。活动控制器是元数据主题的单个分区的领导者,它将接收所有的写入操作。其他控制器是跟随者,将获取这些更改。我们仍然像数据平面一样使用偏移量和领导者epoch。但是,当需要选举领导者时,是通过法定人数(quorum)来完成的。另一个区别是,元数据记录在写入每个节点的本地日志时会立即刷新到磁盘。
KRaft模式下Controller Leader选举过程
1. 初始状态:大家都是小弟(Follower)
- 每个Broker(Kafka服务器)启动时,都是“小弟”(Follower),等着“大哥”(Leader)发号施令。
- 大哥会定期给小弟们发“心跳”(心跳包),告诉大家:“我还活着,继续听我的!”
2.大哥挂了,小弟们开始慌了
- 如果小弟们长时间没收到大哥的心跳,就会觉得:“大哥可能挂了!”
- 这时,小弟们会进入“竞选模式”(Candidate),准备选一个新大哥。
3. 拉票环节:谁能当大哥?
- 每个想当大哥的小弟会给自己加一个“竞选编号”(term),然后向其他小弟拉票:“选我当大哥吧!”
- 其他小弟会根据候选人的“资历”(日志是否够新)来决定是否投票。
4.投票结果:谁票多谁当大哥
- 如果某个候选人拿到超过一半的票(多数票),就会成为新大哥(Leader)。
- 其他小弟会重新变回小弟(Follower),听新大哥的指挥。
关键点总结
- 多数票原则:必须拿到超过一半的票才能当大哥。
- 日志一致性:只有"资历够深"(日志够新)的小弟才能竞选。
- 心跳机制:大哥靠心跳维持地位,小弟靠心跳确认大哥是否活着。