有了多副本,Kafka还是可能丢消息,业务系统怎么办??
消息中间件丢消息的场景非常多,因为使用上的不合理导致的,都很容易解决,比如下面这些:
(1)异步发送。消息在客户端端内存里面,重启丢失。
(2)同步发送,ACK = 1。Broker发生了主从切换,丢消息。
(3)消费方拉取消息之后就ACK,消息还在内存里面,没来得及处理完,挂了重启。
(4)早期的Kafka版本,因为主从复制算法有缺陷,主从来回切换,可能丢消息。后来改成了类似Raft的epoch机制,没有了此问题。
即使所有这些统统都避免了,但因为日常运维问题,导致极小概率的消息丢失偶尔发生。
作为业务系统,没办法完全信任消息中间件的可靠性,但业务又要求一个不能丢,怎么处理呢?
答案是:业务ACK。
系统A给系统B发的消息,在系统B没有给系统A发送ACK之前,系统A的消息在自己的DB里面暂存一份。接受到ACK之后,删除DB消息;超过一定时间,收不到ACK,这些消息重发,直到所有消息都最终删除。
这个ACK,有多种实现方式:可以是系统A提供一个ACK接口供B调用,也可以是再准备一个ACK队列,系统B发送ACK消息,系统A消费ACK消息。ACK消息丢了也不怕,大不了超时没有ACK,系统A重新发送,B重新消费(显然,B必须幂等)。
学过TCP原理的应该会发现:这个ACK + 超时重传机制,和TCP实现可靠传输的原理是异曲同工。把消息中间件类比UDP(不可靠的,可能丢消息),把业务系统类比TCP(可靠的,不丢不重),在一个不可靠的传输通道上实现了可靠的消息传输。
评论