乐趣区

关于kafka:聊聊-KafkaKafka-消息丢失的场景以及最佳实践

一、前言

大家好,我是老周,有快二十多天没有更新文章了,很多小伙伴始终在催更。先阐明下最近的状况,最近我的项目上线很忙,没有工夫写,并且组里有个共事应用 Kafka 不当,导致线上音讯失落,在修复一些线上的数据,人都麻了。事件是这样,有个 Kafka 消费者实例,部署到线下来,生产到了线上的数据,而新版本做了新的逻辑,新版本的业务逻辑与老版本的业务逻辑不兼容,间接导致生产失败,没有进行重试操作,要害还提交了 offset。间接这部分数据没有被业务解决,导致音讯失落,而后紧急修复线上数据。

刚好这些天忙完了有空,所以记录一下,同时看是否对大家能起到防止踩坑的作用,能有一些作用,那我写的也就值了。

咱们上面会从以下三个方面来说一下 Kafka 音讯失落的场景以及最佳实际。

  • 生产者失落音讯
  • Kafka Broker 服务端失落音讯
  • 消费者失落音讯

二、Kafka 的三种音讯语义

先说 Kafka 音讯失落的场景之前,咱们先来说下 Kafka 的三种音讯语义,不会还有人不晓得吧?这个不应该了,音讯零碎基本上形象成这以下三种音讯语义了:

  • 最多传递一次
  • 起码传递一次
  • 仅有一次传递

类型 音讯是否会反复 音讯是否会失落 劣势 劣势 实用场景
最多一次 生产端发送音讯后不必期待和解决服务端响应,音讯发送速度会很快。 网络或服务端有问题会造成音讯的失落 音讯零碎吞吐量大且对音讯的失落不敏感。例如:日志收集、用户行为等场景。
起码一次 生产端发送音讯后须要期待和解决服务端响应,如果失败会重试。 吞吐量较低,有反复发送的音讯。 音讯零碎吞吐量个别,然而绝不能丢音讯,对于反复音讯不敏感。
有且仅有一次 音讯不反复,音讯不失落,音讯可靠性很好。 吞吐量较低 对音讯的可靠性要求很高,同时能够容忍较小的吞吐量。

三、Kafka 音讯失落的场景

3.1 生产者失落音讯

  • 目前 Kafka Producer 是异步发送音讯的,如果你的 Producer 客户端应用了 producer.send(msg) 办法来发送音讯,办法会立刻返回,但此时并不能代表音讯曾经发送胜利了。
  • 如果音讯再发送的过程中产生了网络抖动,那么音讯可能没有传递到 Broker,那么音讯可能会失落。
  • 如果发送的音讯自身不合乎,如大小超过了 Broker 的承受能力等。

3.2 Kafka Broker 服务端失落音讯

  • Leader Broker 宕机了,触发选举过程,集群选举了一个落后 Leader 太多的 Broker 作为 Leader,那么落后的那些音讯就会失落了。
  • Kafka 为了晋升性能,应用页缓存机制,将音讯写入页缓存而非间接长久化至磁盘,采纳了异步批量刷盘机制,也就是说,依照肯定的音讯量和工夫距离去刷盘,刷盘的动作由操作系统来调度的,如果刷盘之前,Broker 宕机了,重启后在页缓存的这部分音讯则会失落。

3.3 消费者失落音讯

  • 消费者拉取了音讯,并解决了音讯,但解决音讯异样了导致失败,并且提交了偏移量,消费者重启后,会从之前已提交的位移的下一个地位从新开始生产,生产失败的那些音讯不会再次解决,即相当于消费者失落了音讯。
  • 消费者拉取了音讯,并提交了生产位移,然而在音讯解决完结之前忽然产生了宕机等故障,消费者重启后,会从之前已提交的位移的下一个地位从新开始生产,之前未解决实现的音讯不会再次解决,即相当于消费者失落了音讯。

四、最佳实际

4.1 生产端

  • 不要应用 producer.send(msg),而要应用 producer.send(msg, callback)。带有回调告诉的 send 办法能够针对发送失败的音讯进行重试解决。
  • 设置 acks = all。代表了你对“已提交”音讯的定义。如果设置成 all,则表明所有正本 Broker 都要接管到音讯,该音讯才算是“已提交”。这是最高等级的“已提交”定义。
  • 设置 retries = 3,当呈现网络的刹时抖动时,音讯发送可能会失败,此时配置了 retries > 0 的 Producer 可能主动重试音讯发送,防止音讯失落。


如果重试达到设定的次数,那么生产者就会放弃重试并返回异样。不过并不是所有的异样都是能够通过重试来解决的,比方音讯太大,超过 max.request.size 参数配置的值时,这种形式就不可行了。

  • 设置 retry.backoff.ms = 300,正当估算重试的工夫距离,能够防止有效的频繁重试。


它用来设定两次重试之间的工夫距离,防止有效的频繁重试。在配置 retriesretry.backoff.ms之前,最好先估算一下可能的异样复原工夫,这样能够设定总的重试工夫大于这个异样复原工夫,以此来防止生产者过早地放弃重试。

4.2 Broker 端

  • 设置 unclean.leader.election.enable = false。它管制的是哪些 Broker 有资格竞选分区的 Leader。如果一个 Broker 落后原先的 Leader 太多,那么它一旦成为新的 Leader,必然会造成音讯的失落。故个别都要将该参数设置成 false,即不容许这种状况的产生。
  • 设置 replication.factor >= 3。其实这里想表述的是,最好将音讯多保留几份,毕竟目前避免音讯失落的次要机制就是冗余。

  • 设置 min.insync.replicas > 1。这管制的是音讯至多要被写入到多少个正本才算是“已提交”。设置成大于 1 能够晋升音讯持久性。在理论环境中千万不要应用默认值 1。

  • 确保 replication.factor > min.insync.replicas。如果两者相等,那么只有有一个正本挂机,整个分区就无奈失常工作了。咱们不仅要改善音讯的持久性,避免数据失落,还要在不升高可用性的根底上实现。举荐设置成 replication.factor = min.insync.replicas + 1

4.3 生产端

  • 确保音讯生产实现再提交。最好把它设置成 enable.auto.commit = false,并采纳手动提交位移的形式。这对于单 Consumer 多线程解决的场景而言是至关重要的。


尽管采纳手动提交位移的形式能够解决生产端音讯失落的场景,但同时会存在反复生产问题,对于反复生产问题咱们下一篇再讲。

  • 像咱们下面说的那个线上问题,即便你设置了手动提交,生产异样了同时也提交了位移,还是会存在音讯失落。

    Kafka 没有重试机制不反对音讯重试,也没有死信队列,因而应用 Kafka 做音讯队列时,须要本人

实现音讯重试的性能。这里我先说下大抵的思路,后续有工夫再分享代码进去:

 - 创立一个 Topic 作为重试 Topic,用于接管期待重试的音讯。- 一般 Topic 消费者设置待重试音讯的下一个重试 Topic。- 从重试 Topic 获取待重试音讯存储到 Redis 的 ZSet 中,并以下一次生产工夫排序。- 定时工作从 Redis 获取达到生产工夫的音讯,并把音讯发送到对应的 Topic。- 同一个音讯重试次数过多则不再重试。
退出移动版