Kafka的消息发送语义

相关文档:https://kafka.apache.org/documentation/#semantics

消息发送保证有三种:

  • 最多一次
  • 至少一次
  • 正好一次

Kafka发送消息时,会有一条committed的日志,committed的消息保证不会被丢失。

当生产者发送消息时遇到网络故障,那么它是没有办法知道这个消息是不是已经被committed。

生产者角度

  1. 至少一次的语义:在0.11.0.0之前,如果生产者没有收到committed的响应,那么它只能再发一遍。
  2. 正好一次的语义:在0.11.0.0之后,kafka提供了幂等发送选项,因此重发不会形成重复的日志。实现方法:每个生产者给了一个ID,每个消息都有一个增长的sequence number用来给消息去重。

0.11.0.0之后还引入了事务语义,发送消息给多个topic partition的时候,要么全部成功,要么全部失败。

消费者角度

消费者会记录自己读到哪里了(offset),不论这个信息存在持久化设备还是内存中,她有这么两种做法:

  1. 最多一次的语义:读取消息,记录offset,处理消息。如果在处理消息前crash,那么下次从offset恢复的时候就有可能丢失上次未处理的消息。
  2. 至少一次的语义:读取消息,处理消息,记录offset。如果记录offset前crash,那么下次从offset恢复的时候就有可能重复处理消息。大多数情况下会在处理消息时保证幂等性。

【正好一次】怎么实现?在从一个Topic A消费消息然后发送消息到另一个Topic B的场景里(Kafka Streams),在消费消息的时候可以同时把offset作为一个消息发送到一个Topic C中,并且这个过程放在事务里,如果事务中断了,那么这个offset消息会回滚,而Topic B也会回滚。再配合Topic B消费者隔离级别设置为read_committed。

在把消息写到外部系统的场景中(比如写到数据库),可以把offset一起写到数据库里,这样就避免了2PC(特别是如果外部系统不支持2PC)。

版权

评论