前段时间实际项目中遇到了一个问题,特此整理下
配置信息
1.kafka集群采用经典部署方式,3节点
2.为了保证全局消息有序性,topic只有一个分区,三个副本
3.生产者和消费者均只有一个,均以主备微服务方式部署
4.消费者通过TCP方式将数据发送给其他服务,这里用对端代替
问题现象
对端收到的稳定数据突然丢失,引发一系列问题
原因排查
1.排查消费者消息日志,可以看到:由于网络问题,消费者异常重启;但是针对该场景,消费者做了故障保护机制,为啥数据会丢失呢?
2.消费者故障保护机制为:重启后,消费者对端先保持消费者发送的数据指定时间(可配置),并且消费者会向生产者请求全量数据。
3.但是对端保持数据时间超时后,消费者依然没有拉取到消费者重启请求的全量数据(这里做过性能测试,保持数据时间 > 生产者生产 + 消费者消费时间)
4.排查生产者日志,发现生产者在生产全量数据时,返回了写入topic错误的异常!进一步排查,发现分区所在磁盘空间已满。。。
5.排查了一轮才发现这个问题,但是为啥磁盘空间满了呢?创建topic时明明设置了log文件最多保存7天以及未消费的数据不清除,难道问题出在了生产者生产的数据未被消费?
6.数据未消费的怀疑很快被否决了,因为使用消费数据的设备明明已经正常运行了两个多月,并且业务是正常的,无奈了。。。。
7.继续分析生产者和消费者日志,突然发现:消费者在消费确认时,报了一个错userdata cannot be null的错,原因是,消费者客户端填充的userdata为null,引发异常,也就是说消费者实际消费到了数据,但是kafka服务端认定数据未被消费过。
问题的根因
1.消费者客户端使用的是C语言客户端rdkafka,它与java客户端kafka-client实现存在差异,即:消费确认时,不会自动填充userdata,而kafka服务端认为userdata未填充是异常场景
2.由于topic的配置为未消费的数据不清理,因此无论过了多久,数据都不会被清理,最终导致磁盘空间爆满