Kafka stream 开发碰到的问题:offset commit 失败 与 数据不准确

最近使用kafka stream来给系统日志做整合统计。我们用elk采集和统计log,但是由于系统log量太大,一天有5G,这个elk中的 elasticsearch 节点就需要存储5G原始数据并且进行索引。必然会占用大量硬盘。所以使用kafka stream来做一个实时聚合,把每5分钟的log数据聚合成一条summary数据,再把聚合结果放到elk中。

然而聚合结果不是很精确。对比原始log,发现聚合完后的结果和原始数据大概有±7 ~ %4的误差。可能的原因有两个:

  1. Consumer group 频繁 rebalance 导致重复处理某些log
  2. 消息的时间戳不是真正写log的时间

第一个问题的原理是: kafkaconsumer 调用 poll 方法来从kafka server 获取消息,同时 poll 方法发送心跳给coordinator(问题: coordinator 是指kafka server 还是指某一个consumer?),说明自己还活着。那么如果一个consumer 调用两次 poll 方法的时间间隔太长,超过了 max.poll.interval,将导致coordinator认为这个consumer已经死亡,那么coordinator会进行group rebalance,把当前consumerpartition分配给别的consumer。这样当前consumer在处理数据后进行commit时会抛出offsetcommit failure异常。然后已经处理完的那些数据会被发给别的consumer重复处理。

解决办法: 修改consumer配置项,max.poll.records 这项在consumer中默认是500,而在kafka stream中默认是1000.意味着如果kafkastream 处理1000条数据太慢,超过了max.poll.interval=6s那么将导致consumerrebalance,最终导致0-1000条的数据重复计算。

解决办法是把max.poll.records设置为300

第二个问题的原理是:从kafka 0.9 开始,kafka 会给每条消息打一个时间戳,这个时间戳可以用于kafka strem中基于时间窗口聚合的时间点。也就是把落在同一个时间窗口的数据聚合到一起。那么这个时间戳可以是kafka 给打的时间戳(问题:是kafkaserver打的还是kafka consumer打的?),也可以是消息体中的某一个时间字段。

那么之前我是使用kafka 打的时间戳来做时间窗口。因为我认为只要那边写一行logkafka stream就进行处理,应该是实时的数据, kafka打的时间戳应该就等于log时间,没必要再去解析log时间。而事实上,从kafkastream的日志中看到,这个时间戳比log时间滞后了20多分钟。那么很可能是由于kafka stream处理慢导致log堆积在kafka server上,等到真正进入kafka stream 处理时已经在log产生之后的20分钟了。

解决办法是自己实现kafkastream API 提供的 TimeExtractor 接口,从消息中提取真正的logTime作为时间戳。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值