提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Kafka的消息传递语义
kafka
对消息传递的语义保证(消息的可靠传输)提供了三种保证:
- At most once(最多一次) - 消息可能会丢失,但永远不会重新传递(消息丢失)。
- At least once (最少一次)- 消息永远不会丢失,但可能重新传递(重复消费)。
- Exactly once (仅一次)- 每条消息只传递一次(可靠传递)。
注意: 这分为两个问题:① 发布消息的持久性保证 ② 消费消息的持久性保证
精准一次
的消息传递语义,需要生产者和消费者共同保证。
生产者端
At most once
(最多一次)
如果Producer
发送消息的时候,Broker
发生了网络错误,且Producer
没有进行retry
操作
At least once
(最少一次)
如果Producer
消息成功发送,但没有接收到来自Broker
消息已提交的响应,只能选择重新发送
消费者端
At most once
(最多一次)
在这种情况下,在刚刚提交完offset之后还没来得及处理消息之前崩溃,那么就会发生At most once (最多一次)语义,即被提交还未处理的消息可能再也不会被处理了,也就是“消息丢失”。
At least once
(最少一次)
在这种情况下,消费者进程可能已经消费完消息了但是在准备提交offset前崩溃了,这时被处理过的消息就可能被新的消费者进程重复处理(重复消费),这对应At least once(至少一次)语义,即消息被重复处理——重复消费。
生产者acks应答配置
acks: -1 # 应答级别:多少个分区副本备份完成时向生产者发送ack确认(可选0、1、-1/all)
- 0 Producer只要发送即成功
- 1 Producer发送成功且leader落盘,broker ack之后 才成功
- -1/all 分区所有副本全部落盘,broker ack之后 才成功
我们可以理解为
Acks=0/1时,消息发送的语义为 At most once
(最多一次)
Acks=-1/all,retries > 0时,消息发送的语义为 At least once
(最少一次)
消费者自动提交配置
enable-auto-commit:
- true:自动提交,消息消费的语义为
At most once
(最多一次)
,例:当消费者poll请求到消息后,不论处理消息是否发生异常,均会自动提交偏移量。 - false:手动提交,消息消费的语义为
At least once
(最少一次)
,消费者代码中需要显式提交偏移量。
消息的可靠传递
生产者:精确一次
- enable.idempotence=true
- retries=Integer.MAX_VALUE // enable.idempotence=true 时,自动设置retries次数为最大
- Acks=all
生产者:精确一次
在消息中加入唯一ID(例如流水ID,订单ID),在处理业务时,通过判断ID来防止重复处理
消息事务
当从 Kafka 主题消费并生产到另一个主题时(如在 Kafka Streams 应用程序中),可以利用 0.11.0.0 中的事务功能。 消费者的位置作为消息存储在主题中,因此我们可以在与接收处理数据的 输出主题 相同的事务中将偏移量写入 Kafka。如果事务被中止(事务回滚),消费者的位置将恢复到它的旧值,并且 输出主题 的产生的数据将对其他消费者不可见,这取决于他们的“隔离级别”。在默认的read_uncommitted
隔离级别中,所有消息对消费者都是可见的,即使它们是被回滚的事务的一部分,但在read_committed
中,消费者将只返回来自已提交事务的消息(以及任何不属于事务的消息)。
总结
在Kafka中可以通过Kafka事务提供 Exactly once“仅一次”的交付,与其他系统的精确的一次交付通常需要这些系统合作,单Kafka提供了offset实现起来更加可行。否则Kafka默认只保证至少一次传递,并且允许用户在处理一批消息之前通过禁用生产者的重试机制和在消费者中提供offset(先提交再处理)来实现最多一次交付。