在kafka开发中遇到的问题及解决方案

文章目录

      • 问题一
      • 问题二
      • 重点释惑采坑记
      • 避免重复消费的处理
      • 目前重复消费的问题说明
      • 后记

kafka 后端埋点数据实时同步到 GP集群,出现重复消费问题有两方面的原因。

问题一

由于gp集群的并发量限制,每到任务提交的高峰期,执行一条sql并返回结果需要排队很长时间,一旦排队时间大于5分钟,
就会大于kafka consumer 两批poll(long)方法之间默认的处理时间。处理线程会认为此consumer 挂掉,
进而引发rebalance,导致重复消费数据。
解决方案:
通过调大两次批处理之间的间隔来跨越GP集群在任务高峰期的等待时间,以此来提高容错能力。参数为:max.poll.interval.ms

问题二

由于可能某个批次时间段之内需要通过poll(long)方法拉取的数据比较大,在默认的两次心跳间隔之内不能处理完数据,
心跳线程会认为此consumer死掉,进而引发rebalance,导致重复消费数据。
解决方案:
调大两次心跳进程之间的时间间隔,提高容错能力,参数据为: session.timeout.ms 与heartbeat.interval.ms

重点释惑采坑记

在Kafka 0.10.0.0(含)版本之前只有session.timeout.ms参数,在这之后引入了max.poll.interval.ms参数。
通过后台心跳线程与处理线程将heartbeats与poll()的调用解耦.这允许比心跳间隔更长的处理时间(即,两次连续轮询poll()之间的时间)。
由于我以前的开发版本基本上都是基于kafka 0.10.0.0之前的版本,所以在这里踩了一个大坑。

避免重复消费的处理

如果只有以上处理也不能避免kafka重复消费的问题,只能尽量减少rebalance,以此来减少重复消费。因此我又坐了下面的处理
想要避免发生kafka consumer rebalance时的重复消费问题,只能把每条数据的处理与kafka consumer偏移量的管理放到一个事物内或者
保证两次处理之间的原子性。
但是由于针对我们的场景,想方设法把每条数据的处理与kafka consumer偏移量的管理放到一个事物内的代价太大(需要大量IO交互和大量的与GP集群的交互),
因此我把每次消费完以后kafka consumer 的偏移量存储到外部设备,尽量做到在一个事物内。这样当kafka 发生rebalance时,就会从外部设备重新读取偏移量,
从而避免重复消费数据。
这样虽然没有把对每条数据的处理与kafka consumer偏移量的管理放到一个事物内,保证恰号一次(exactly-once)的语义。
但经过大量测试数据没有发生重复消费的问题。由于没有保证恰号一次语义,发生重复消费的几率应该会存在,但也是微乎其微,
数据的准确率会达到99.999%以上。理论上数据不会丢失,实际上数据也没有发生丢失的情况。

目前重复消费的问题说明

3.24号08:40左右发现有数据重复消费的情况出现。经过排查验证是kafka服务源端数据发生了重复导致的,
经验kafka运维人员沟通,他们的策略是是尽量保证不丢,可以允许有少量重复。

后记

由于我是每消费一条或者一批数据都会都会做一次偏移量的存储,可能会有人就会认为我做了大量不必要的开销,浪费了大量IO操作。
因为网上很多关于kafka的文章关于在ConsumerRebalanceListener这个监听类的onPartitionsRevoked方法内做偏移量的存储工作。
经过测试这里会有一个问题,就是当kafka的consumer的增加或者kafka的分区数增加引起的Rebalance,这样做没问题,
但是如果是kafka consumer的减少引发的Rebalance时候, 由于此consumer 已经挂掉,不能调用ConsumerRebalanceListener的onPartitionsRevoked方法
去存储当前分区消费的偏移量,就会导致重复消费。

参考:
Kafka session.timeout.ms heartbeat.interval.ms参数的区别以及对数据存储的一些思考

你可能感兴趣的:(kafka)