卡夫卡的确切的一次语义是最近引入的版本, 使消息被准确地传递给最终消费者, 即使生产者重试发送消息。
这一主要版本引起了社会各界的广泛关注, 因为人们认为在分布式系统中这不是数学上可能的。克列普斯, 联合创始人和 Apache 卡夫卡, 解释了它的可能性, 它是如何实现在卡夫卡在这篇文章。
在本博客中, 我们将讨论如何利用卡夫卡提供的完全一次的消息语义。
Apache 卡夫卡提供的不同消息传递语义概述
“在大多数一次-m带有可能会丢失, 但从来没有重新传送.
在这种情况下, 当 ACK 超时或返回错误时, 生产者不会重试发送消息, 因此消息可能最终不会写入卡夫卡主题, 因此不会传递给使用者。
“至少有一次, 消息永远不会丢失, 但可能会重新传送.
在这种情况下, 如果 ACK 超时或收到错误, 则生产者尝试重新发送邮件, 前提是该邮件未写入卡夫卡主题。
” 恰好一次– 这是人们真正想要的, 每条消息只传递一次, 只有一次.
在这种情况下, 即使生产者尝试重新发送一条消息, 它也会导致消息被完全传递给最终使用者。
准确地说, 语义是最可取的保证, 需要消息系统本身与生成和使用消息的应用程序之间的合作。
例如, 如果在成功使用邮件后, 您将卡夫卡消费者退回到以前的偏移量, 您将从该偏移量中接收到最新的所有消息, 并再次出现。这说明了为什么消息传递系统和客户端应用程序必须进行合作, 使语义恰好发生。
为什么要使用卡夫卡的完全一次语义?
我们知道至少有一次保证每条消息至少保持一次, 不会丢失任何数据, 但这可能会导致流中的重复。
例如, 如果代理在发送 ACK 之前失败, 但在邮件成功写入卡夫卡主题后, 此重试将导致消息被写入两次, 因此会多次传递给最终使用者。
在新的完全一次语义中, 卡夫卡的处理语义保证了消息向最终消费者传递的准确一次。通过引入以下方法加强了这一点:
-
Idemptotent 生产者
-
原子事务
幂等生产者
幂等运算是一种操作, 可以多次执行, 而不会造成不同的效果, 而不是仅执行一次操作。
现在, 在卡夫卡中, 生产者发送的操作可以是幂等的, 这样, 如果发生导致生产者重试的错误, 由生产者多次发送的同一条消息只会写入到维护的卡夫卡经纪商的日志中。
幂等生产者确保在单个生产者的生存期内, 消息仅在特定主题分区中传递一次。
若要打开此功能并获取每个分区的完全一次语义-这意味着没有重复项、无数据丢失和按顺序语义-使用以下属性配置生产者:
enable
当代理或连接失败时, 并且生产者尝试重新发送邮件时, 仅当该邮件的序列号超过最后一条消息时, 才会接受该消息。
但是, 如果生产者失败并重新启动, 它将得到一个新的 PID。因此, 幂等性仅在单个生产者会话中得到保证。
原子事务
卡夫卡现在支持跨多个分区通过新的事务 API 进行原子写入。这样, 生产者就可以将一批消息发送到多个分区, 这样批处理中的所有消息都对所有使用者都可见, 或者任何用户都看不到。
它允许您在同一个事务中与您处理的数据一起提交用户偏移量, 从而允许端到端的完全一次语义。
下面是一个示例代码段, 描述如何使用新的生产者 API 将消息以原子方式发送到一组主题分区:
{
producer.initTransactions();
try{
producer.beginTransaction();
producer.send(record0);
producer.send(record1);
producer.sendOffsetsToTxn(…);
producer.commitTransaction();
} catch( ProducerFencedException e) {
producer.close();
} catch( KafkaException e ) {
producer.abortTransaction();
}
}
消费者
若要使用事务, 您需要将使用者配置为采用正确的隔离. 级别并使用新的生产者 api。卡夫卡消费者现在有两个新的隔离级别:
- read_committed: 在提交事务后, 读取这两种类型的消息 (不属于事务的一部分)。
- read_uncommitted: 在不等待提交事务的情况下, 按对方顺序读取所有邮件。此选项与卡夫卡使用者的当前语义类似。
此外, 必须将事务性. id属性设置为生产者配置中的唯一 id。此唯一 ID 是在应用程序重新启动期间提供事务性状态连续性所必需的。
引用
- 汇合的博客上完全一次语义
- 在 Apache 卡夫卡的交易
- 用于比较至少一次语义的有利和消失案例的图像源