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事务能够保证多分区消息发布时要么全部成功,要么全部失败。(原子性)