消息丢失问题

1. 消费端丢失数据

默认情况下,Kafka 会自动提交 Offset,Kafka 认为 Consumer 已经处理消息了,但是 Consumer 可能在处理消息的过程中挂掉了。重启系统后,Consumer 会根据提交的 Offset 进行消费,也就丢失了一部分数据。

解决:关闭自动提交 Offset,在处理完之后自己手动提交 Offset,就可以保证数据不会丢失。但可能会存在消息重复消费问题。

2. Kafka 丢失数据

比较常见的一个场景:Kafka 某个 Broker 宕机,然后重新选举新的 Leader ,但此时其他的 Follower 部分数据尚未同步,结果此时 Leader 挂了,然后选举某个 Follower 成 Leader ,丢失一部分数据。

所以此时一般设置如下 4 个参数:

  • Topic 设置 replication.factor 参数
    参数值必须大于 1,要去每个 Partition 必须有至少 2 个副本。
  • Kafka 服务端设置 min.insync.replicas 参数
    参数值必须大于 1,要去每个 Partiton 必须有至少 2 个副本。
  • Producer 设置 acks=all
    要求每条数据,必须是写入所有副本,才认为写成功
  • Producer 端设置 retries=MAX
    MAX 即是一个超级大的数字,表示无限次重试。retries=MAX要求一旦写入数据失败,就无限重试。

3. Producer 丢失数据

如果 Producer 端设置了 acks=all,则不会丢失数据。

Leader 在所有的 Follower 都同步到了消息之后,才认为本次写成功。如果没满足这个条件,生产者会进行无限次重试。

消息重复消费问题

原理

Consumer 消费了数据后,每个一段时间,会将已消费过的消息的 Offset 进行提交,这样,重启后,可以继续从上次消费过的 Offset 来继续消费。测试时,直接 kill 进程,然后再重启后,会导致 Consumer 将有些消息处理了,但是还未来得及提交 Offset,重启后,少数消息会再消费一次。

解决

需要结合具体业务来思考,可从以下几个思路来考虑:

  • 如果要将数据写入数据库中,先根据主键查查询,如果这数据已存在,就不用插入数据了。
  • 向 Redis 中写入数据,可以使用 set,这样数据不会重复
  • 基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。