kafka消费者连接topic分区失败造成消息大量堆积

晚上7点收到topic堆积告警,经检查,发现消费者到topic分区断连,分区覆盖率下降为0,由于业务TPS高,所以几分钟内即形成上千万条消息堆积,业务成功率下降明显,第一时间怀疑晚上高峰期业务量大,带宽消耗大,网络不稳定造成的,所以第一时间增加消费方的超时时间(socket.timeout.ms)并重启,消费者随即连接成功,重新开始消费,堆积逐渐减小,业务逐渐恢复。

但一周不到再次出现同样的问题,分区覆盖降到0,可是上次增加消费超时时间之后并未还原,所以再次出现之后觉得很奇怪。

查看消费方日志,发现几分钟内都没有打印新日志,于是,将日志级别调整为debug,发现是获取之前的消费位置offset失败:Could not fetch offsets (because offset cache is being loaded).结合consumer启动流程来看:consumer初始化->连接负载均衡,给连接分配要绑定的分区->连接访问kafka集群的Controller获取上次消费的位置(当前就是这里有问题,一直获取不到)->从上次消费的位置开始向后消费

报错内容:because offset cache is being loaded,是说kafka正在加载offset信息,kafka维护offset数据,是自己创建了一个内部的_consumer_offset的Topic,该topic存储消费者的消费进度,当前业务消费者的offset是优先提交到kafka的,同时也提交到zookeeper,所以会优先从kafka读取,只有当kafka没有的时候才会尝试去zookeeper读取,但是当前kafka并非没有,只是正在加载,可见_consumer_offset队列长期处于加载中,正是问题所在。

问题分析到这里,暂且不展开分析_consumer_offset被重新加载的原因,现网问题的处理原则在任何时候都是恢复业务放在首位,所以我们采取修改消费者配置,提交方式修改为优先提交到zookeeper,同时提交到kafka,这样消费者也会优先从zookeeper读取offset,修改后重启,业务逐渐恢复,至此消费者的启动流程已经修改为:consumer初始化->连接负载均衡,给连接分配要绑定的分区->连接直接访问zookeeper集群获取上次消费的位置->从上次消费的位置开始向后消费。(修改消费提交方式为在消费者的配置文件中添加offsets.storage=zookeeper)

业务恢复后,再来看_consumer_offset为何被重新加载,进一步排查消费端和kafka端的日志文件,发现连续出现2次zookeeper session超时(目前kafka以zookeeper来做集群管理与节点发现),默认超时时间为zookeeper.session.timout.ms=6000ms,错误日志如下:

kafka的controller.log:

ZK expired; shut down all controller components and try to re-elect (kafka.controller.KafkaController$SessionExpirationListener)

Closing socket connection to XXXX(业务主机)

re-registering broker info in ZK for broker 1

Registered broker 1 at path /brokers/ids/1 with address XXXX:9092(kafka主机)

done re-registering broker

Subscribing to /brokers/topics path to watch for new topics

.

.

New leader is 2

断连两次,kafka重新加入集群,可以认为kafka重启了两次,每次都需要重新加载topic _consuer_offset:

第一次断连,offset数据最长加载时间为200000+ms:

FInishing loading offsets from [_consuer_offsets,14] in 200000 milliseconds;

第二次断连,offset数据最长加载时间达到了6000000+ms:

FInishing loading offsets from [_consuer_offsets,14] in 6000000 milliseconds;

分析队列加载耗时原因:_consuer_offsets分区数据巨大,84亿条,且分布不均,分区49有34亿条数据,这与topicID和groupid命名有关,不展开讨论,造成topic分区数据巨大的原因是为尽可能保证消息不丢失,该topic的清除策略配置为压缩不删除cleanup.policy=compact.

综上,改进建议如下:

1、修改__consumer_offset的cleanup.policy=delete,保留时间为15天,减少topic保存的数据量,减少kafka加载压力;

2、增加zookeeper.session.timout.ms超时时间,配置为30s,减少由于网络抖动或者磁盘cpu、网卡IO影响导致kafka与zookeeper断连

在问题已修复,已定位之后,进一步回头来看最根本原因,kafka与zk之间为何断连,查看主机zabbbix历史数据来看,在断连发生时,cpu的iowait是异常高的,由此可以看出来是由于kafka主机瞬时磁盘IO导致的kafka与zk的心跳阻塞,所以除了以上两点改进之外,还需要进一步分析kafka主机的性能瓶颈,进行性能优化或者集群横向扩容。

 

 

 

 

你可能感兴趣的:(kafka消费者连接topic分区失败造成消息大量堆积)