一、前言
博主现在负责触达平台的建设,众所周知,对于4000万客户的推送来说,高流量的推送会导致系统负载更高,所以就会使用大量的消息队列来缓冲请求,达到削峰;但是由于网络抖动或者流量高峰期间可能会存在一些报错,现在记录下来并作为分享。
二、生产者问题整理
问题一:生产者写入超时
现象:
org.apache.kafka.common.errors.TimeoutException: Expiring 59 record(s) for mkt_push_statistics_filter-7: 30375 ms has passed since batch creation plus linger time
【[CAT异常告警]】
>**内容摘要**:<font color="warning">[异常告警]: [ 异常名称: TimeoutException 异常总量:1528.0 ]
[业务负责人: lili5 ] [告警间隔时间]5分钟</font>
>**告警节点**:ext-spring-jyyx-mkt-push-channel
>**告警级别**:<font color="warning">P0</font>
>**告警时间**:2021-05-13 20:40:04
>**故障ID**:4bca28cc0638bc3fc36a3db0ae9eac59
>**告警来源**:CAT
>**详情访问**:[Solaris告警平台](https://solaris.xxx.cn/solarisHistory/alert-detail?eventId=4bca28cc0638bc3fc36a3db0ae9eac59)
分析:
生产者发送超时,根据报错信息分析是否是代码问题,因为一直没有报错,突然报一波,怀疑是网络抖动,然后分析到生产者一般都是批量提交消息到brocker处,肯定会超时时间,查了request.time.out默认视为30s,现在刚好到达改时间;
具体原因如下:
producer send方法的callback函数执行缓慢导致;
producer往broker发送数据时是串行的,只有上次batch全部写入broker,并且全部callback函数执行完毕后,才会继续下一次发送。如果上一次发送全部callback函数执行时间超过了request.timeout.ms(30s),就会导致后续batch的message发送时间大于创建时间30s以上,然后被producer丢弃并抛出异常;
解决办法:
1、增大request.time.out=60m;
2、根据业务增加重试次数和重试间隔
关于重试,我想说几点:
第一:一般kafka默认重试间隔是100ms,我们设置重试次数为3,所以恢复该数据需要花费:30000*3+200=900200ms,约等于90秒 一分钟半,一半情况网络抖动 不会立刻恢复,所以会导致重试后还是失败的;
第二:如果系统对数据为弱一致性,允许一定量消息丢失时,这种少量的重试后失败的,可以忽略;
第三:如果对数据要保持最终一致性,即保证消息不可丢失时,可以对抛出的异常进行捕获并持久化到数据库中,然后进行job补偿;
问题二:消费者提交offset失败
问题:
1. [Consumer clientId=consumer-2, groupId=messageBoxMessageListener] Offset commit failed on partition mkt_push_box_message-7 at offset 40771: The coordinator is not aware of this member;
[Consumer clientId=consumer-2, groupId=directPushMessageListener] Offset commit failed on partition mkt_direct_push_customer_message-1 at offset 8306283: The coordinator is not aware of this member.
elk查询如下:
分析:
1、consumer group 消费者组,consumer消费者,group coordinator组协调者,主要管理消费者组的健康状态和分区分配问题;
2、在一个线程(用户线程)里面执行kafka consumer 的while true循环逻辑的,其实这里有2个线程:一个是用户线程,另一个是心跳线程。心跳线程,主要根据heartbeat.interval.ms参数配置的值周期性向coordinator发送心跳包以证明consumer还活着;
3、每次poll消息太多,消息处理逻辑过重,调用三方接口超时,也即用户线程需要执行很长的时间处理消息,然后再提交offset,这时达到pool最大间隔时间了,会发生reblance;
session.timeout.ms:consumer group coordinator在多少秒内没有没收到consumer 心跳命令时就会认为当前consumer死了,然后会触发rebalance
heartbeat.interval.ms:consumer实例间隔多少ms向consumer group coordinator发 join group的命令表示自己活着
max.poll.interval.ms:消费者线程每次poll的最大间隔时间
max.poll.records:每次poll消息的最大条数,默认是500
解决措施:
1、对kafka消费者参数调整:
增大max.poll.interval.ms至10分钟(默认五分钟)
降低 max.poll.records至200,默认为500
提高session.timeout.ms至15秒,默认为6秒;
2、指定推送消息幂等校验(后期);