Kafka005——聊聊Broker

291 阅读12分钟

写在前面

近期看到有篇文章说,找到一件可以产生效益的事情,然后持之以恒,迭代的只有完成它的方法,而不需要变更执行它的决心。

我觉得说的很对。

很喜欢士兵突击。当时看时以为我是成才,傻子才是许三多。现在回头想想,才发现能当许三多是很难的事情。

人太聪明了,聪明到会考虑很多,结果忘了最原初的事情。

道理人人都懂,事情人人都能做。但许三多才会去做,才成了兵王。

所以,找到坚持有益的事情,然后就是坚持与提高它的效率。然后就是陪着自己和时间慢慢走。

基础知识

Broker是什么

Broker可以看做是一台Kafka服务器,但其实是运行在一台网络服务器上的进程。它有如下作用:

  1. 接收Producer写入消息的请求
  2. 接收Consumer拉取消息的请求
  3. 负责消息的持久化存储(内存->硬盘)
  4. 负责Partition的不同Replicas之间的数据同步与故障迁移

Broker的生命周期

  1. 启动阶段:当Broker启动时,它会加载配置文件,初始化日志管理器,创建网络层和请求处理层,连接到ZooKeeper,并注册自己到集群。如果集群没有Controller,它也会尝试竞选成为Controller。
  2. 运行阶段:当Broker运行时,它会处理来自生产者和消费者的请求,包括写入和读取数据,以及同步和复制数据。如果Broker是Controller,它还会处理来自其他Broker的请求,包括管理集群的元数据,分配和转移分区,选举和切换Leader等。同时,Broker也会与ZooKeeper保持心跳通信,检测集群的状态和变化。
  3. 重新选举阶段:当Broker失去与ZooKeeper的连接或者宕机时,它会退出Controller角色,并释放/controller目录的锁。此时,ZooKeeper会通知其他broker开始新一轮的选举。原来的Controller会尝试重新竞选,如果成功,它会恢复到运行阶段;如果失败,它会成为Follower,并等待下一次选举。
  4. 关闭阶段:当Broker关闭时,它会先停止接收新的请求,并等待已有的请求完成。然后,它会关闭网络层和请求处理层,断开与ZooKeeper的连接,并从集群上注销自己。最后,它会关闭日志管理器,并释放资源。

Broker有哪些配置项

通过配置项可以直接从参数的角度来了解Broker。参数有很多,这里只覆盖了一部分。但能从这些参数来看到Broker有自己服务器维度、网络连接、与ZooKeeper交互、Log存储、消费者与消息多维度的参数设置。

Broker Server基础配置

  • broker.id:整个Kafka集群内标识唯一Broker的ID。整数类型。这个值其实也是ZooKeeper在 /brokers/ids 路径下创建的节点ID。若不指定,或者指定为-1,那么ZooKeeper就会从 reserved.broker.max.id 这个参数(默认1000)加1,用作Broker的ID
  • delete.topic.enable:是否允许删除Topic。
  • auto.create.topics.enable:是否允许在Producer在未指定Topic发送Message时自动创建Topic。

Broker Socket 配置

  • listeners:Broker之间,Client与Broker之间通信建立连接时使用的信息。即Broker的监听者,可以以逗号分割配置多个。它的格式为[安全协议]://Hostname/IP:Port。Kafka支持两种传输层协议(PLAINTEXT或SSL)(加密消息)与两种认证层安全协议(SSL或SASL)(认证客户端与服务器身份)。
  • advertised.listeners:将Broker建立通信的地址发布到Zookeeper中,便于Client(Producer和Consumer)连接。它的格式和listener一致。
  • listener.security.protocol.map:以Key/Value的形式定义监听者的安全协议,在大多数情况下会将Key认为是监听者的别名。
  • inter.broker.listener.name:设置内部通信时使用哪个监听者。可以直接设置listener.security.protocol.map中设置的Key。
  • num.network.threads:Broker Server接收请求及发送响应时启用的线程数量。
  • num.io.threads:Broker Server处理请求、对Message进行I/O操作时启用的线程数。

Broker Log 配置

Broker Log存储也是很重要的内容,这里先按下不表。

  • log.dirs:日志、Message保存的路径。
  • num.partitions:创建Topic时,如果没有指定Partition数量,则使用该配置项设置的Partition数量。
  • num.recovery.threads.per.data.dir:每个数据目录启用几个线程来处理,这里的线程数和数据目录数是乘积关系,并且只在Broker启动或关闭时使用。具体如下:
    • 当服务器正常启动时,用于打开每个分区的日志片段。
    • 当服务器发生崩溃并重启时,用于检查和截断每个分区的日志片段。
    • 当服务器正常关闭时,用于关闭日志片段。
  • min.insync.replicas:当acks=all时,至少有多少个Replicas需要确认已持久化数据,包括Leader。
  • log.retention.hours:Kafka保留Message的时间,默认是168小时,即7天。
  • log.retention.check.interval.ms:检测Message是否可以被删除的时间间隔。
  • log.retention.bytes:已保留的消息的字节总数来判断旧消息是否过期,这个值对应的是每一个分区,如果一个topic有3个分区,这个值设为1GB, 那么该主题最多保留3GB数据。
  • log.segment.bytes:每个Segment文件的大小,默认是1G。当日志大小超过该值时,下一次日志写入就会创建一个新的segment。

Broker ZooKeeper 配置

2.7版本还在使用,之后3.x版本已经不使用了。

  • zookeeper.connect:设置Zookeeper地址。可用逗号分割配置多个地址,既Zookeeper集群的地址。
  • zookeeper.connection.timeout.ms:等待连接Zookeeper的超时时间。

Consumer Group 配置

  • group.initial.rebalance.delay.ms:当Consumer Group新增或减少Consumer时,重新分配Topic Partition的延迟时间。

Message 配置

  • message.max.bytes:Broker接收每条Message的最大值,默认是1M。
  • fetch.message.max.bytes:Consumer每次获取Message的大小。

Broker集群原理是什么?

Kafka可以设置多个Broker来实现分布式架构,提供良好的水平扩展性,可以支持大吞吐量的消息处理能力。而多个Broker通过构成一个集群,那么多个Broker之间是如何协调的?相互如何通信?

如何管理Broker?

Kafka通过Controller与ZooKeeper(2.7版本之前)来实现对Broker的管理。

Broker的启动与下线

当一个Broker启动时,它会做以下这些事情:

  1. 初始化:加载配置文件、初始化日志管理器等初始化动作;
  2. 注册:连接到ZooKeeper,并在ZooKeeper的/brokers/ids路径下创建一个临时节点来注册自己(填入配置的broker.id
  3. 监听:注册自己之后,还会监听 /brokers/ids这个路径节点,当这个节点下增加或删除子节点时,ZooKeeper 会通知监听了的 Broker。
  4. 竞选:如果当前集群没有Controller,那么Broker还会尝试竞选Controller。

当一个Broker下线时,它会做以下这些事情:

  1. 停止:停止接受新的请求,并等待处理中的请求完成;
  2. 关闭:关闭与网络和请求处理层的连接,断开与ZooKeeper的连接,删除之前注册的节点。关闭日志管理器,释放连接资源。

Controller

Controller是Broker中的Leader,非Controller的Broker就是Follower。他有如下用途:

  1. 管理和协调Kafka集群的元数据,分区的分配和状态转移,以及处理Broker的故障
  2. 管理主题的创建、删除、增加分区等操作
  3. 管理分区的重分配、领导者选举、负载均衡等操作
  4. 监控集群成员的变化,包括broker的增加或减少、宕机或恢复等
  5. 向其他broker提供数据服务,包括同步集群元数据、分区信息、副本信息等

Controller的生命周期

  1. 初始化阶段:当Broker启动时,它会尝试在ZooKeeper的/controller目录下创建一个临时节点,并写入自己的broker.id,从而竞选成为Controller。如果成功,它会初始化Controller的上下文,包括集群的元数据、分区状态机、副本状态机、事件管理器等。如果失败,它会成为Follower,并监听/controller目录的变化。
  2. 运行阶段:当Broker成为Controller后,它会在运行阶段处理各种事件,例如Broker的增加或减少、Topic的创建或删除、Partition的分配或转移、Leader的选举或切换等。这些事件会由Controller事件管理器来调度和执行,根据不同的事件类型,触发不同的控制器动作。同时,Controller也会与其他Broker保持心跳通信,检测Broker的可用性和健康状况。
  3. 重新选举阶段:当Broker失去与ZooKeeper的连接或者宕机时,它会退出Controller角色,并释放/controller目录的锁。此时,ZooKeeper会通知其他Broker开始新一轮的选举。原来的Controller会尝试重新竞选,如果成功,它会恢复到运行阶段;如果失败,它会成为Follower,并等待下一次选举。
  4. 销毁阶段:当Broker关闭时,它会销毁Controller相关的资源,包括上下文、状态机、事件管理器等,并从ZooKeeper上注销自己。

Controller的选举流程

答案就隐藏在上面的生命周期中。具体来说有如下情况:

  1. 当集群启动时,每个Broker都会尝试在ZooKeeper的/controller目录下创建一个临时节点,并写入自己的broker.id;
  2. ZooKeeper保证只有一个Broker能够成功创建/controller节点,该Broker就成为Controller,负责管理集群的元数据和状态。
  3. 其他Broker会监听/controller目录的变化,如果发现/controller节点被删除,就会重新开始竞选。
  4. 当Controller宕机或失去与ZooKeeper的连接时,会删除/controller下的临时节点,并释放/controller节点的锁。此时,ZooKeeper会通知其他Broker开始新一轮的竞选。
  5. 原来的Controller会尝试重新竞选,如果成功,它会恢复到运行状态;如果失败,它会成为Follower,并等待下一次竞选。

Controller要做哪些事

  • 监听ZooKeeper上不同的目录。
    • /admin:这个目录用于存储集群中的管理操作,包括删除Topic、增加分区、重新分配分区等。当有管理操作被触发时,这个目录会更新。监听这个目录来实现Controller处理Topic创建、删除、增加分区等操作;
    • /brokers/ids:这个目录用于存储集群中所有活跃的broker信息,包括broker.id、host、port、rack等。当broker加入或离开集群时,这个目录会更新。监听这个目录来实现Controller监控集群成员与处理Partition的分配与转义等操作;
    • /brokers/topics:这个目录用于存储集群中所有的topic信息,包括topic名称、分区数量、副本分配等。当topic被创建或删除时,这个目录会更新;监听这个目录来实现Controller响应Topic创建删除等操作;
    • /controller:这个目录用于存储当前的controller信息,包括broker.id和controller epoch。当controller发生变化时,这个目录会更新。监听这个目录用于触发Controller的重选举流程;
    • /isr_change_notification:这个目录用于存储集群中的ISR(同步副本集合)变化通知,包括分区名称和新的ISR列表。当ISR发生变化时,这个目录会更新;监听这个目录可以用于提供可靠的消息生产ACK机制。
  • 维护元数据信息
    • 调用ZooKeeper的API来创建、更新、删除、获取、监听,包括Broker、Topic、Partition、Replica在内的集群元数据信息;
      • Controller也会在自己内存中维护这些信息的缓存,用于处理其他Broker获取这些数据的请求
      • Controller也会使用Kafka内部特殊的Topic来生产、消费与同步这些元数据信息
  • 维护Partition分配与状态
    • Partition分配:由kafka内部的分配策略来决定的,例如DefaultReplicaPlacementStrategy、RackAwareReplicaPlacementStrategy等。用户也可以自定义自己的分配策略,通过实现BrokerRackAwareness接口来定义;
    • 维护分区状态机
      • 维护每个Partition的状态:NonExistentPartition、NewPartition、OnlinePartition、OfflinePartition。
      • Controller来协调和控制各个状态的转移。
  • 维护副本状态机。
    • 维护每个Partition Replica的状态,包括NewReplica、OnlineReplica、OfflineReplica等。
    • Controller来协调和控制各个状态的转移。

(这里有很多内容是关于Kafka如何管理Partition的,包括内部的多个Replica,这里先按下不表,在独立介绍几个模块角色之后,希望能通过具体的操作流程来串联整体)

综合

Broker在一次消息写入时起到了哪些作用?

  1. 接收消息:Broker接收生产者发送的消息,并将其存储在本地磁盘的分区分段文件中。Broker还会为每个分段文件创建索引文件,以便快速查找消息
  2. 同步消息:如果Broker是某个分区的Leader副本,它还会将收到的消息同步给其他的Follower副本,以实现数据的备份和高可用性。Broker可以配置同步方式(同步或异步)和同步策略(ISR或Quorum)
  3. 响应确认:Broker在完成消息的接收和同步后,会根据生产者的acks设置返回相应的确认信息,以通知生产者消息是否写入成功

Broker在消息消费时充当了哪些角色?

  1. 提供消息:Broker根据Consumer的请求,从本地磁盘的分区分段文件中读取相应的消息,并返回给Consumer]。
  2. 维护消费位移:Broker会为每个Consumer Group维护一个消费位移(offset),用来记录该Group已经消费到哪个位置。Consumer可以根据自己的消费情况,定期提交消费位移给Broker,也可以查询Broker的消费位移来确定消费的起始位置]。
  3. 处理Rebalance:Broker会监测Consumer Group内部的变化,比如有新的Consumer加入或者有Consumer退出,然后触发重平衡(rebalance)操作,重新分配每个分区的消费者。Broker会通知Group Leader进行分区分配,并将结果同步给其他的Consumer]。

Broker是如何完成消息的存储的?

这个内容就太多了,放在下一篇吧。

参考资料

  1. juejin.cn/post/684490…
  2. www.modb.pro/db/615537