1. Partition的作用
Topic是逻辑的概念,Partition是物理的概念:
- Partition 对一个 Topic 的消息进行物理上的分离,让消息可以分布在不同的实体机器上,可以提升系统吞吐量和并行处理能力。
- 每个Partition可以有多个副本(Leader和Follower),Leader负责读写操作,Follower负责数据同步。将消息备份在副本中,可以确保高可用性。
举个例子,更形象的理解Partition 和 Topic:
- Topic 比作高速公路,不同的 Topic就是不同的高速公路
- Partition 比作车道,有的公路是 3 车道,有的是 4 车道,车道可以提升公路的运输能力
Partition的目的是:通过多Partition实现负载均衡的效果,提高kafka集群的吞吐率。
2. 消息写入Partition
一个 Topic 有多个 Partition,生产者向一个 Topic 中发送消息的时候,有3种写入方式:
- kafka默认轮询规则
- producer指定partition key写入特定的partition
- producer自定义规则
3. 消息消费
假设主题T1有四个分区。
3.1 一个消费群组
3.1.1 partition数量 > 消费者数量
只有一个消费者时,消费者1将收到所有分区的全部消息。
当有两个消费者时,每个消费者将分别从两个分区接受消息。
3.1.2 partition数量 = 消费者数量
当有四个消费者时,每个消费者都可以接受一个分区的消息。
3.1.3 partition数量 < 消费者数量
当有五个消费者时,会有闲置的消费者。
3.2 多个消费群组
消费者群组之间是互不影响的:
4. 分区分配策略
Kafka的分区分配策略决定了如何将Topic的各个Partition分配给消费者组内的消费者,以实现消息的并行消费。这些策略通过配置参数partition.assignment.strategy来指定。主要的分区分配策略包括:
- RangeAssignor(范围分配器):
Kafka的默认分区分配策略。它首先将所有Partitions按分区编号排序,然后将消费者按字母顺序排序。之后,将Partitions均匀地“分配”给消费者,尽量使每个消费者分配到连续的Partition区间。这种方式有利于保持消息的顺序性,特别是在消费者组中的消费者数量少于或等于分区数时。 - RoundRobinAssignor(轮询分配器):
这种策略将分区在消费者间进行轮询分配,确保每个消费者尽可能平均地获得相同数量的Partitions。相比RangeAssignor,它不保证分区的连续性,但能更好地分散负载,尤其是在消费者数量远大于分区数的情况下。 - StickyAssignor(粘性分配器 / 粘性分配策略):
引入于Kafka 0.10.1版本,这是一种更高级的分配策略,旨在结合RangeAssignor和RoundRobinAssignor的优点。它试图在重新平衡时保持分配的稳定性(即尽量保持之前分配给消费者的Partitions不变),同时确保分区尽可能均匀地分布在消费者之间。这种策略减少了频繁的rebalance操作导致的性能开销,提高了整体的稳定性。
5. 分区Rebalance
触发分区分配策略的情景:
- 消费者组成员变化:当有新的消费者加入或已有消费者离开消费者组时,会触发重新分配。
- 订阅列表变化:如果消费者修改了其订阅的Topic列表,也会引起分配策略的重新执行。
- Broker或Partition变化:Kafka集群的Broker增加、减少或Topic的分区数发生变化时,需要重新分配分区。
- Session超时:消费者长时间未发送心跳给组协调者(通常由Zookeeper或Kafka自身的GroupCoordinator服务担任),被视为已离线,从而触发再平衡。
- 手动触发:在某些情况下,管理员或应用程序可以通过API调用来手动触发消费者的再平衡。
每次触发Rebalance时,Kafka会依据配置的分区分配策略重新计算分区到消费者的映射关系,以达到最佳的负载均衡状态。但是也会消耗大量网络资源和CPU资源,导致在Rebalance期间消费性能下降、集群不稳定,可能导致消息延迟、消息挤压、消息重复消费等异常。为了缓解上述问题,通常采取的措施包括优化Rebalance触发条件、合理配置消费者参数、使用更高效的分区分配策略(如StickyAssignor)、以及确保消费者及时提交偏移量等。