位移管理
reblance
consumer定期向kafka提交自己的位移信息,这个位移通常是下一条待消费
的消息的位置
说到位移就不得不提一下HW(High Watermark)
,水位的概念,HW是指消费者能读到的最新消息的位移,HW之下的消息
rablance的触发条件
- 组成员发生变更时:消费者离开组(不一定是崩溃,有可能是消费者执行的消费逻辑过重,在指定时间之内无法完成消息处理,会被coordinator认为离线,也有可能是主动离开),新的消费者加入组
- 组订阅的topic数目发生变化 :eg:基于正则表达式的订阅,新增加了topic会导致reblance
- 组订阅的topic分区数目发生变化,命令行修改了topic的分区数目
reblance策略
- range
基于范围,将单个topic的分区按照顺序排列,并划分成固定大小,一次分配给每个消费者 - round-robin
所有topic的分区一次排开,轮询分配给每个消费者 - sticky
上述两种方案,无视历史分配方案,可以规避数据倾斜并在两次reblance之间最大限度的保持了之前的分配方案
rebalance generation
这个数据保护了consumer group,有效避免了过期位移提交的问题。
rebalance generation初始为0,每次触发rebalance,都将+1。
过期位移提交问题
某些情况下,consumer没有能够及时提交offset,这期间kafka进行了一次rebalance,rebalance generation = N+ 1.但是这时候,consumer的提交信息姗姗来迟,但是他携带的rebalance generation = N,这时候kafka会忽略这个无效的提交
rebalance 协议
- JoinGroup协议:consumer请求加入组
- SyncGroup协议: group leader把分配方案同步到组内所有成员中
- HeartBeat协议: consumer定期向coordinator汇报心跳代表自己还活着
- LeaveGroup协议: consumer 主动通知coordinator自己就要离开消费者组
- DescribeGroup协议:查看组的所有信息,包括成员信息、协议信息、分配方案和订阅信息等。主要供管理员使用
consumer根据heartbeat的响应中是否包含REBALANCE_IN_PROCESS来判断当前group是否开启新一轮rebalance
rebalance流程
- 获取coordinator所在broker
一个消费者组
在进行rebalance之前,必须先确定coordinator所在的broker。
计算的方式是:- 计算
Math.abs(groupID.hashCode)%offsets.topic.num.partitions
- 假设结果等于3,去寻找当前这个topic分区3的leader所在的broker,她就是这个
group
的coordinator
- 计算
- 加入组
组中所有成员向coordinator
发送JoinGroup请求,coordinator
选择一个consumer作为这个group
的leader
,
注意,leader是 某个consumer的实例,而coordinator是kafka集群的的某个broker,是leader而非coordinator负责为整个consumer group的成员定制分配方案 - 同步更新分配方案
消费者组内所有成员向coordinator
发送SyncGroup请求,但是只有leader发送给coordinator
的请求中包含了分配方案;coordinator
接收到leader
发送的分配方案后将每个consumer负责的方案单独封装作为SyncGroup请求的响应返回给各自的consumer.
注意,consumer group的分配方案是在consumer端进行的,kafka将这种分配的权利下方给客户端是因为这样可以有更好的灵活性:
* 这种机制下用户可以自行实现“机架感知”功能,同一个机架上的分区数据被分配给相同机架上的consumer,就近分配,减少不必要的网络传输。
* 分区策略发生变更,只需要重启consumer,不必重启kafka服务器
rebalance监听器
新版本consumer默认将位移数据提交到topic _consumer_offsets
中,同时可以通过实现接口ConsumerRebalanceListener
将位移提交到外部存储中,如数据库等(真的有人会用这个功能吗?这样岂不是增加了系统的复杂性?什么场景下要用这个功能呢?有人知道的话一定告诉我啊!)
使用前提:
必须使用consumer group
,如果是独立consumer或者是手动分配分区,监听器无效