暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

线上问题排查(11)--Kafka消息生产过快引发的问题

架构经纬 2024-11-12
224

【每天5分钟,了解一个知识点】

一、问题背景

假设现在有一个场景,需要跑定时任务去读取一张五千万级别的大表,然后把数据推送到 Kafka,中间不做任何逻辑处理。

二、问题出现及错误分析

当这个定时任务运行起来后,出现了问题。采取紧急停止定时任务的措施后,依然有陆续的报错信息。这是因为定时任务可能一时之间无法立刻停下来,存在滞后性。不过系统倒是一直正常运行着。

RuntimeException 
org.apache.kafka.common.errors.TimeoutException
ERROR Exception thrown when sending a message with key='null' and payload='{"item_id":104592403,"item_type":"family_members","project":"production","type":"item_set","properti...' to topic TOPIC_MEMBER_DATA:
org.apache.kafka.common.errors.TimeoutException: Expiring 57 record(s) for TOPIC_MEMBER_DATA-8: 30001 ms has passed since batch creation plus linger time

错误日志显示出现了TimeoutException
异常,大致意思是有 57 条记录经过 30001ms 加上滞留时间后变成了过期记录。

三、排查过程

  1. 首先检查代码是否存在问题。由于上线之前在测试环境中已经验证过,而且业务代码本身也不复杂,所以一开始就排除了代码的问题。

  2. 接着排查 Kafka 集群是否异常。和运维人员一起排查后,发现集群情况很正常,消息也能正常写入,排除了集群出问题的可能。

  3. 最后排查 Kafka 客户端及深入 Kafka 生产者。既然服务端正常,那就得看看客户端的情况。从报错信息中发现了“expiring 过期”和“linger time 滞留时间”这两个有价值的信息。因为这里是纯生产者,所以深入研究一下生产者。

    系统使用的是默认参数,查询资料后找到了一些比较有用的参数,比如request.timeout.ms
    linger.ms
    。当消息生产速度过快时,发送的速度远小于生产消息的速度。消息生产后会存在类似消息容器的ProducerBatch
    中,放进去后会继续生产不管有没有发送。在将消息放进ProducerBatch
    时会设置一个过期时间,即request.timeout.ms
    (默认 30000ms),超时后就会报异常并从发送队列中剔除这条消息。

四、解决方案

原有的发送是采用异步发送的形式,目的是为了快,结果因为太快出了问题。那就抛弃异步,采用同步发送的形式。

这里顺便给大家讲讲 Kafka 发送消息的三种方式:

(1)发后即忘就好比你寄信,只管把信扔进邮筒,也不管信能不能准确送达。大多数情况下没什么问题,但有时候(比如出现不可重试的异常时)会造成消息丢失。这种方式性能最高,但可靠性最差。

(2)异步发送一般是在发送消息的时候指定一个回调函数,当 Kafka 返回响应时就会调用这个函数来实现异步的发送确认。有人可能会问,发送消息的方法返回值是Future
Future
本身也能做异步处理呀。这样做不是不行,只是Future
里的get()
方法什么时候调用、怎么调用都是问题。消息不停发送,众多消息对应的Future
对象处理起来会让代码逻辑变得混乱。而使用回调函数的方式就简洁明了,Kafka 有响应时就会回调,要么发送成功,要么抛出异常。

(3)同步发送这种方式可靠性高,要么消息发送成功,要么发生异常。如果发生异常,可以捕获并进行相应处理,不会像“发后即忘”的方式直接造成消息丢失。不过同步发送的方式性能会差很多,需要等一条消息发送完才能发送下一条。

【关联阅读】

关注公众号,回复【Java面试】,获取更多面试资料

文章转载自架构经纬,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论