Kafka无消息丢失
Kafka的消息丢失有几种情况
- 生产者程序丢失消息
- 消费者程序丢失消息
- Kafka本省弄丢了消息
我们一一来说:
生产者程序丢失了消息
场景是你的Producer向Kafka发消息,但是发现Kafka没有保存
解决方案:
一定要使用producer.send(msg,callback),带回调通知的发送API
在有错误的情况下,要根据情况做处理
消费者程序丢失消息
Kafka本身平时消费的时候都是默认提交offset的
所以有可能存在我们消费的时候有问题,但是又默认提交了,导致消息丢失的情况
所以我们要先消费,再提交。
当然这也会带来另外一个问题,就是可能出现重复消费,譬如先消费了,然后这个程序宕机了,虽然已经消费了,但是却没有提交。
Kafka弄丢了消息
我们知道 Kafka 为分区(Partition)引⼊了多副本(Replica)机制。分区(Partition)中的多个
副本之间会有⼀个叫做 leader的家伙,其他副本称为follower。我们发送的消息会被发送到
leader 副本,然后 follower 副本才能从 leader 副本中拉取消息进⾏同步。⽣产者和消费者只与
leader 副本交互。你可以理解为其他副本只是 leader 副本的拷⻉,它们的存在只是为了保证消息
存储的安全性。
试想⼀种情况:假如 leader 副本所在的 broker 突然挂掉,那么就要从 follower 副本重新选出
⼀个 leader ,但是 leader 的数据还有⼀些没有被 follower 副本的同步的话,就会造成消息丢失。
设置acks=all
解决办法就是我们设置 acks = all。acks 是 Kafka ⽣产者(Producer) 很重要的⼀个参数。
acks 的默认值即为1,代表我们的消息被leader副本接收之后就算被成功发送。当我们配置 acks
= all 代表则所有副本都要接收到该消息之后该消息才算真正成功被发送。
设置 replication.factor >= 3
为了保证 leader 副本能有 follower 副本能同步消息,我们⼀般会为 topic 设置 replication.factor
>= 3。这样就可以保证每个 分区(partition) ⾄少有 3 个副本。虽然造成了数据冗余,但是带来了
数据的安全性。
设置 min.insync.replicas > 1
⼀般情况下我们还需要设置 min.insync.replicas> 1 ,这样配置代表消息⾄少要被写⼊到 2 个副
本才算是被成功发送。min.insync.replicas 的默认值为 1 ,在实际⽣产中应尽量避免默认值
1。
但是,为了保证整个 Kafka 服务的⾼可⽤性,你需要确保 replication.factor >
min.insync.replicas 。为什么呢?设想⼀下加⼊两者相等的话,只要是有⼀个副本挂掉,整个
分区就⽆法正常⼯作了。这明显违反⾼可⽤性!⼀般推荐设置成 replication.factor =
min.insync.replicas + 1。
设置 unclean.leader.election.enable = false
Kafka防止消息重复消费
对于不需要幂等性的消息,这个就无所谓了,但是如果是需要幂等性的,那么就需要防止消息重复消费了。
我们假设一个场景,如果Kafka是用于解耦的,比如发邮件啥的。
那就无所谓了,就算多发一个邮件也没啥对吧,而且也一般会做验证,看redis里是否有验证码什么的,消息也一般不会发过去两次。就算发过去了,检查一下Redis有没有验证码也都可以解决。
但是如果是电商,加积分这种情况,就必须引入数据库或者其他中间件了,譬如你去给数据库做一个唯一约束,然后订单号固定的情况下,你是没办法给流水表插两条的,这样就会失败,自然没法加两次了。
另外一种是参考乐观锁的机制,譬如你发消息时账户里有50积分,然后要加五十积分,你传过去的消息如果为在有50积分的情况下加五十积分,那肯定就不会重复消费了
那么我们能解决的方法主要就是三种
- 用Redis存key,每次消费的时候看key是否消费过
- 用MySQL的唯一约束,让第二次消费的记录插入无效
- 设置前置条件,只有满足前置条件,才消费(这个还是有问题)