kafka消息传递语义

现在我们对生产者和消费者的工作方式有了一些了解,让我们来讨论 Kafka 在生产者和消费者之间提供的语义保证。 显然,可以提供多种可能的消息传递保证:

  • 最多一次——消息可能会丢失,但永远不会重新发送。

  • 至少一次——消息永远不会丢失,但可能会重新发送。

  • 恰好一次——这是人们真正想要的,每条消息只传递一次。

值得注意的是,这分为两个问题:发布消息的持久性保证和消费消息时的保证。

许多系统声称提供“恰好一次”交付语义,但阅读细则很重要,这些声明中的大多数是误导性的(即它们没有转化为消费者或生产者可能失败的情况,存在多个 消费者进程,或写入磁盘的数据可能丢失的情况)。

Kafka 的语义是直截了当的。 当发布消息时,我们有一个消息被“提交”到日志的概念。 一旦提交了已发布的消息,只要复制该消息所写入分区的broker保持“活动”,它就不会丢失。 已提交消息的定义、活动分区以及我们尝试处理的故障类型的描述将在下一节中更详细地描述。 现在让我们假设一个完美的无损broker,并尝试了解对生产者和消费者的保证。 如果生产者尝试发布消息并遇到网络错误,则无法确定此错误是发生在消息提交之前还是之后。 这类似于使用自动生成的键插入数据库表的语义。

在 0.11.0.0 之前,如果生产者未能收到表明消息已提交的响应,则它别无选择,只能重新发送消息。 这提供了至少一次传递语义,因为如果原始请求实际上已经成功,则消息可能会在重新发送期间再次写入日志。 从 0.11.0.0 开始,Kafka 生产者还支持幂等传递选项,以保证重新发送不会导致日志中出现重复条目。 为此,broker为每个生产者分配一个 ID,并使用生产者随每条消息发送的序列号对消息进行重复数据删除。 同样从 0.11.0.0 开始,生产者支持使用类似事务的语义将消息发送到多个主题分区的能力:即所有消息都已成功写入或没有消息写入成功。 主要用例是 Kafka 主题之间的恰好一次处理(如下所述)。

并非所有用例都需要如此强大的保证。 对于延迟敏感的用途,我们允许生产者指定其所需的持久性级别。 如果生产者指定它要等待正在提交的消息,则这可能需要 10 毫秒的时间。 然而,生产者也可以指定它想要完全异步地执行发送,或者它只想等到领导者(但不一定是追随者)收到消息。

现在让我们从消费者的角度来描述语义。 所有副本都具有完全相同的日志和相同的偏移量。 消费者控制其在此日志中的位置。 如果消费者从未崩溃,它可以只将这个位置存储在内存中,但是如果消费者失败并且我们希望这个主题分区被另一个进程接管,新进程将需要选择一个合适的位置开始处理。 假设消费者读取一些消息——它有几个选项来处理消息和更新其位置。

  1. 它可以读取消息,然后将其位置保存在日志中,最后处理消息。 在这种情况下,消费者进程有可能在保存其位置之后但在保存其消息处理的输出之前崩溃。 在这种情况下,接管处理的进程将从保存的位置开始,即使该位置之前的一些消息尚未处理。 这对应于“最多一次”语义,因为在消费者失败消息的情况下可能不会被处理。

  2. 它可以读取消息,处理消息,并最终保存其位置。 在这种情况下,消费者进程有可能在处理消息之后但在保存其位置之前崩溃。 在这种情况下,当新进程接管它收到的前几条消息时,它已经被处理了。 在消费者失败的情况下,这对应于“至少一次”语义。 在许多情况下,消息有一个主键,因此更新是幂等的(两次接收相同的消息只会用它自己的另一个副本覆盖一条记录)。

那么恰好一次语义(即你真正想要的东西)呢? 当从 Kafka 主题消费并生产到另一个主题时(如在 Kafka Streams 应用程序中),我们可以利用上面提到的 0.11.0.0 中新的事务性生产者功能。 消费者的位置作为消息存储在主题中,因此我们可以在与接收处理数据的输出主题相同的事务中将偏移量写入 Kafka。 如果交易被中止,消费者的位置将恢复到其旧值,并且其他消费者将无法看到输出主题上产生的数据,这取决于他们的“隔离级别”。 在默认的“read_uncommitted”隔离级别中,所有消息对消费者都是可见的,即使它们是中止事务的一部分,但在“read_committed”中,消费者只会返回来自已提交事务的消息(以及任何不属于该事务的消息) 交易)。

写入外部系统时,限制在于需要协调消费者的位置与实际存储为输出的内容。 实现这一点的经典方法是在消费者位置的存储和消费者输出的存储之间引入两阶段提交。 但这可以通过让消费者将其偏移量存储在与其输出相同的位置来更简单、更一般地处理。 这更好,因为消费者可能想要写入的许多输出系统不支持两阶段提交。 举个例子,考虑一个 Kafka Connect 连接器,它在 HDFS 中填充数据以及它读取的数据的偏移量,以便保证数据和偏移量都被更新,或者都不更新。 对于需要这些更强语义并且消息没有允许重复数据删除的主键的许多其他数据系统,我们遵循类似的模式。

因此,Kafka 有效地支持 Kafka Streams 中的一次性交付,并且在 Kafka 主题之间传输和处理数据时,通常可以使用事务性生产者/消费者来提供一次性交付。 其他目标系统的 Exactly-once 交付通常需要与此类系统合作,但 Kafka 提供了使实现这一点可行的偏移量(另见 Kafka Connect)。 否则,Kafka 默认保证至少一次交付,并允许用户通过在处理一批消息之前禁用对生产者的重试和在消费者中提交偏移量来实现至少一次交付。

0 0 投票数
文章评分

本文为从大数据到人工智能博主「xiaozhch5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://lrting.top/backend/2427/

(0)
上一篇 2021-11-25 19:02
下一篇 2021-11-25 19:53

相关推荐

订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x
()
x