Kafka消息交付可靠性保障

Kafka消息交付可靠性保障

Kafka 消息交付可靠性保障以及精确处理一次语义的实现。

Kafka 对 Producer 和 Consumer 提供的消息交付可靠性保障:

  • 最多一次(at most once):消息可能会丢失,但绝不会被重复发送。
  • 至少一次(at least once):消息不会丢失,但有可能被重复发送。
  • 精确一次(exactly once):消息不会丢失,也不会被重复发送。

Kafka 默认提供的交付可靠性保障是第二种,即至少一次。

假设消息成功“提交”,但 Broker 的应答没有成功发送回 Producer 端(比如网络出现瞬时抖动),那么 Producer 就无法确定消息是否真的提交成功了。因此,它只能选择重试,也就是再次发送相同的消息,回带来消息重复发送问题。

实现最多一次只需要禁止重试机制就可以实现。

Kafka实现精准一次语义需要基于幂等性(Idempotence)和事务(Transaction)

kafka 消息幂等性

设置Producer端参数enable.idempotence,开启幂等性

props.put(“enable.idempotence”, ture)
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true)

Producer 升级成幂等性 Producer后,其他所有的代码逻辑都不需要改变。Kafka 自动帮你做消息的重复去重。

它只能保证单分区上的幂等性,无法保证跨分区,跨会话的幂等性。即一个幂等性 Producer 能够保证某个主题的一个分区上不出现重复消息,它无法实现多个分区的幂等性。其次,它只能实现单会话上的幂等性,不能实现跨会话的幂等性。这里的会话,你可以理解为 Producer 进程的一次运行。当你重启了 Producer 进程之后,这种幂等性保证就丧失了。

kafka 消息事务性

设置事务型 Producer ,需要满足两个要求:

  • 和幂等性 Producer 一样,开启 enable.idempotence = true
  • 设置 Producer 端参数 transactional. id。最好为其设置一个有意义的名字。

此外,Producer端代码也需要一些事务性的代码:

producer.initTransactions();
try {
            producer.beginTransaction();
            producer.send(record1);  // 消息1
            producer.send(record2);  // 消息2
            producer.commitTransaction();
} catch (KafkaException e) {
            producer.abortTransaction();
}

实际上即使写入失败,Kafka 也会把它们写入到底层的日志中,也就是说 Consumer 还是会看到这些消息。因此在 Consumer 端,读取事务型 Producer 发送的消息也是需要一些变更的,设置 isolation.level 参数的值即可:

  • read_uncommitted:这是默认值,表明 Consumer 能够读取到 Kafka 写入的任何消息,不论事务型 Producer 提交事务还是终止事务,其写入的消息都可以读取。如果你用了事务型 Producer,那么对应的 Consumer 就不要使用这个值。
  • read_committed:表明 Consumer 只会读取事务型 Producer 成功提交事务写入的消息。当然了,它也能看到非事务型 Producer 写入的所有消息。

Kafka官网,对事务有如下论述:

Transactional delivery allows producers to send data to multiple partitions such that either all messages are successfully delivered, or none of them are.

大概是说,Kafka事务能够保证多分区消息发布时要么全部成功,要么全部失败。(原子性)

参考:

https://cloud.tencent.com/developer/article/1383487

posted @ 2022-08-12 13:16  sixinshuier  阅读(203)  评论(0编辑  收藏  举报