消息系统一般有以下的语义:
At most once:消息可能丢失,但不会重复投递
At least once:消息不会丢失,但可能会重复投递
Exactly once:消息不丢失、不重复,会且只会被分发一次(真正想要的)
- Producer 发送消息以后,有一个commit的概念,如果commit成功,则意味着消息不会丢失,但是Producer有可能提交成功后,没有收到commit的消息。这有可能造成 at least once 语义。
- 从 Consumer 角度来看,我们知道 Offset 是由 Consumer 自己维护。所以何时更新 Offset 就决定了 Consumer 的语义。如果收到消息后更新 Offset,如果 Consumer crash,那新的 Cunsumer再次重启消费,就会造成 At most once 语义(消息会丢,但不重复)。
- 如果 Consumser 消费完成后,再更新 Offset。如果 Consumer crash,别的 Consumer 重新用这个 Offser 拉取消息,这个时候就会造成 at least once 的语义(消息不丢,但多次被处理)。
所以结论:默认Kafka提供at-least-once语义的消息分发,允许用户通过在处理消息之前保存位置信息的方式来提供at-most-once语义。如果我们可以实现消费是幂等的,这个时候就可以认为整个系统是Exactly once的了。