Kafka学习笔记(4)——负载均衡

分区副本机制

每个Topic可以有多个Partition, 用于实现高伸缩、负载均衡, 同时每个Partition可以有多个副本(Replica), 用于实现Kafka的高可用.

Leader Replica

每一个Partition有且只有1个Replica可以作为Leader, 负责处理Producer、Consumer的请求, 并负责监管和维护ISR中所有Follower的滞后状态.

Follower Replica

每个Partition除了Leader以外的Replica都是Follwer, 不处理来自客户端的请求, 只通过Fetch Request拉取Leader Replica的数据进行同步.

Leader选举

Broker Controller负责整个集群中的分区和副本的状态, 它会监听其他Broker的信息, 一旦有一个Broker宕机, Controller会读取该Broker上所有Partition在ZooKeeper上的状态, 并遍历ISR列表中的每个Replica, 决定哪一个成为新的Partition leader, 同时更新分区的ISR列表.

ISR机制

每个分区都有一个ISR列表, 用于维护所有同步的、可用的副本, Leader Replica会追踪和维护ISR中所有Follower Replica的滞后状态, Follower Replica需要满足以下条件才被认为是同步的Replica:

  • 与ZooKeeper之间有一个活跃的会话, 定时向ZooKeeper发送心跳;
  • 在规定的时间内从Leader Replica低延迟地获取过消息.

如果不满足以上状态, Leader Replica会把该Replica从ISR移除.

acks机制

当Leader Replica接收到一条消息, 等待ISR中所有Replica都同步复制完成, 该消息才能被消费, 保证消息不丢失, 但如果Replica数量较大, 每条消息都同步完成耗时较大, 需要在一致性和可用性上做权衡, 设置参数request.required.acks:

  • 0: 生产者不等待来自Broker的确认, 继续发送下一条消息. 延迟低, 吞吐量高, 但可靠性低.
  • 1: 生产者收到来自Leader的确认后发送下一条消息, 默认值.
  • -1: 生产者等待ISR中所有Follower的确认后发送下一条消息, 只要至少一个Replica存活就不会丢失数据, 损失性能换来数据的健壮性.

Segment

Partition不是最小的存储单元, 每个Partition由一个或多个Segment组成, 所有的Segment均存在于所属Partition目录下. 每一个Segment都以所存储的第一个消息的上一个Offset为文件名, 可以通过二分查找迅速找到所属的Segment.

消息投递的负载均衡

Producer发送消息时必须指定Topic, 但不必指定Partition, Kafka会进行负载均衡, 把消息均衡分布到Topic下的分区上, 也可以手动指定分区.

  • Kafka默认的分区机制:
    • 如果不指定分区key, 使用轮询算法将消息均衡地分布到各个分区上;
    • 如果分区key参数不为null, 使用内置的hash算法将消息分布到各个分区上.
  • 自定义分区:
    • 生产者发送消息时, 手动指定分区;
    • 自定义Partitioner.

Consumer Group 负载均衡

当发生以下情况时, 会导致Consumer Group的负载均衡(Rebalance):

  • 订阅的Topic数量发生变化;
  • 订阅的Topic分区数发生变化;
  • Consumer个数发生变化.

Rebalance发生时, 消费者组下所有的Consumer都会一起参与, 保证尽量达到公平分配, 但会使所有Consumer停止工作, 直到Rebalance完成.

Consumer个数发生变化是意外发生Rebalance的主要原因. 减少Rebalance情况的出现的可选参数:

  • 设置session.timeout.msheartbeat.interval.ms, 使得Consumer不会因为没有及时发送心跳而被认为下线;
  • 设置max.poll.interval.ms, 让Consumer有足够时间消费消息, 防止因为处理消息时间太长而触发Rebalance.