消息丢失问题
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,这样数据不会重复
- 基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。