Kafka 节点重启失败导致数据丢失的分析排查与解决之道

本文分析了一起因Kafka节点重启失败引起的数据丢失问题,涉及Kafka日志分析、源码理解及解决思路。在非正常退出情况下,Kafka索引文件可能损坏,导致无法启动。通过查看源码,发现在重建索引过程中可能出现错误,导致节点无法重启。解决方案包括删除损坏文件重启节点、优化集群配置和升级Kafka版本。此外,文章提出在分区不可用时允许手动设置副本为leader的建议,以减少数据丢失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

在 2 月10 号下午大概 1 点半左右,收到用户方反馈,发现日志 kafka 集群 A 主题 的 34 分区选举不了 leader,导致某些消息发送到该分区时,会报如下 no leader 的错误信息:

In the middle of a leadership election, 

there is currently no leader for this partition and hence it is unavailable for writes.

由于 A 主题 34 分区的 leader 副本再 broker0,另外一个副本由于速度跟不上 leader,已被踢出 ISR,0.11 版本的 Kafka 的 unclean.leader.election.enable 参数默认为 false,表示分区不可在 ISR 以外的副本选举 leader,导致了 A 主题发送消息持续报 34 分区 leader 不存在的错误,且该分区还未消费的消息不能继续消费了。

接下来运维在 kafka-manager 查不到 broker0 节点了处于假死状态,但是进程依然还在,重启了好久没见反应,然后通过 kill -9 命令杀死节点进程后,接着重启失败了,导致了如下问题。

Kafka 日志分析

查看了 KafkaServer.log 日志,发现 Kafka 重启过程中,产生了大量如下日志:

Kafka 节点重启失败导致数据丢失的分析排查与解决之道

 

发现大量主题索引文件损坏并且重建索引文件的警告信息,定位到源码处:

kafka.log.OffsetIndex#sanityCheck

Kafka 节点重启失败导致数据丢失的分析排查与解决之道

 

按我自己的理解描述下:

Kafka 在启动的时候,会检查 kafka 是否为 cleanshutdown,判断依据为 ${log.dirs} 目录中是否存在 .kafka_cleanshutDown 的文件,如果非正常退出就没有这个文件,接着就需要 recover log 处理,在处理中会调用 sanityCheck() 方法用于检验每个 log sement 的 index 文件,确保索引文件的完整性:

  • entries:由于 kafka 的索引文件是一个稀疏索引,并不会将每条消息的位置都保存到 .index 文件中,因此引入了 entry 模式,即每一批消息只记录一个位置,因此索引文件的 entries = mmap.position / entrySize;
  • lastOffset:最后一块 entry 的位移,即 lastOffset = lastEntry.offset;
  • baseOffset:指的是索引文件的基偏移量,即索引文件名称的那个数字。

索引文件与日志文件对应关系图如下:

Kafka 节点重启失败导致数据丢失的分析排查与解决之道

 

判断索引文件是否损坏的依据是:

_entries == 0 || _lastOffset > baseOffset = false // 损坏

_entries == 0 || _lastOffset > baseOffset = true // 正常

这个判断逻辑我的理解是:

entries 索引块等于零时,意味着索引没有内容,此时可以认为索引文件是没有损坏的;当 entries 索引块不等于 0,就需要判断索引文件最后偏移量是否大于索引文件的基偏移量,如果不大于,则说明索引文件被损坏了,需要用重新构建。

那为什么会出现这种情况呢?

我在相关 issue 中似乎找到了一些答案:

Kafka 节点重启失败导致数据丢失的分析排查与解决之道

 

  • https://issues.apache.org/jira/browse/KAFKA-1112
  • https://issues.apache.org/jira/browse/KAFKA-1554

总的来说,非正常退出在旧版本似乎会可能发生这个问题?

有意思的来了,导致开机不了并不是这个问题导致的,因为这个问题已经在后续版本修复了,从日志可看出

### Kafka 数据丢失的常见原因 Kafka 数据丢失通常发生在以下几种场景中: 1. **生产者(Producer)端消息未成功发送至 Broker** Kafka 的生产者默认采用异步发送方式,如果消息在网络传输过程中因波动或其他原因未能成功到达 Broker,且未开启重试机制或回调确认机制,就可能导致数据丢失。例如,消息过大超出 Broker 的接收限制,也可能导致 Broker 拒收消息[^3]。 2. **Broker 端数据未持久化即发生故障** Kafka 依赖日志文件将消息持久化到磁盘。如果 Broker 在消息写入内存但尚未刷盘时发生故障,可能导致数据丢失。此外,节点重启失败也可能导致部分未持久化的数据丢失[^1]。 3. **消费者(Consumer)端处理不当** 消费者可能在处理消息时发生异常,而未提交偏移量(offset),导致 Kafka 认为该消息已被成功消费,从而引发数据丢失。此外,消费者在提交偏移量前崩溃,也可能导致消息被跳过[^1]。 4. **上下游组件导致数据丢失** Kafka 通常作为数据管道连接其他系统(如 Flume、HDFS 等)。如果上游组件(如 Flume)未能成功发送数据Kafka,或者下游组件未能正确消费 Kafka 中的数据,也会被误认为是 Kafka 数据丢失[^2]。 5. **分区策略不当导致消息分布不均** 如果分区策略设计不合理,例如未正确处理 key 的哈希值,可能导致某些分区未被正确选中,进而导致消息未被正确写入或读取,造成数据丢失”的假象[^4]。 --- ### Kafka 数据丢失排查方法 1. **检查生产者端配置** - 确认是否启用 `acks=all`,确保消息被写入所有副本后再确认发送成功。 - 启用重试机制(如 `retries > 0`)以应对网络波动。 - 设置合理的 `max.in.flight.requests.per.connection`,避免消息乱序。 2. **分析 Broker 端日志配置** - 检查 Broker 是否因消息过大而拒绝接收,可调整 `message.max.bytes` 和 `replica.fetch.max.bytes`。 - 确保 `log.flush.interval.messages` 和 `log.flush.interval.ms` 设置合理,避免消息因未及时刷盘而丢失。 - 查看 Kafka 日志文件,确认是否有异常重启或宕机记录。 3. **验证消费者端行为** - 确保消费者使用 `enable.auto.commit=false` 并在处理完消息后手动提交偏移量。 - 使用 `isolation.level=read_committed` 防止读取到未提交的事务消息。 - 监控消费者的消费延迟,确保其处理能力生产速率匹配。 4. **排查上下游系统** - 检查上游组件(如 Flume)是否正常运行,是否存在数据积压或错误日志。 - 确认下游组件(如 HDFS Sink)是否正确消费 Kafka 消息,并将数据写入目标系统。 5. **审查分区副本配置** - 检查分区器是否按预期工作,确保 key 的哈希值处理正确。 - 确保副本因子(replication factor)设置为 3 或更高,以提高容错能力。 - 使用 `kafka-topics.sh --describe` 查看分区副本的同步状态。 --- ### Kafka 数据丢失的解决方案 1. **增强生产者可靠性** ```java Properties props = new Properties(); props.put("acks", "all"); // 确保消息被所有副本确认 props.put("retries", 3); // 启用重试机制 props.put("retry.backoff.ms", 1000); // 重试间隔 props.put("request.timeout.ms", 30000); // 请求超时时间 ``` 2. **优化 Broker 配置** - 设置 `unclean.leader.election.enable=false`,防止非 ISR(In-Sync Replica)副本成为 Leader,避免数据丢失。 - 启用 `log.cleanup.policy=compact` 对关键主题进行日志压缩,保留最新状态。 3. **提升消费者健壮性** - 手动提交偏移量以确保消息处理完成后再提交: ```java consumer.commitSync(); // 同步提交 ``` - 使用 Kafka 的事务机制确保生产者和消费者操作的原子性。 4. **加强上下游系统监控** - 部署监控系统(如 Prometheus + Grafana)对 Kafka 及其上下游组件进行实时监控。 - 设置告警规则,如生产消费速率不匹配、偏移量滞后等。 5. **定期进行灾难恢复演练** - 模拟 Broker 宕机、网络分区等场景,验证 Kafka 集群的容错能力。 - 定期备份 Kafka 数据至外部存储(如 HDFS、S3),以便在极端情况下恢复数据。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值