Kafka设计(6)消息传递语义

参考文档: http://kafka.apache.org/documentation/#design

消息传递语义

现在我们了解了一点消费者和生产者如何工作,让我们来讨论下消费者和生产者间的语义保证(semantic guarantees)。很明显有多种可能的消息传递担保形式:

  • 最多一次:消息可能会丢失但不会被多次传递
  • 至少一次:消息不会丢失但可能会重新传递
  • 精确一次:这是人们真正想要的,每个消息被传递有且仅有一次。

很多系统宣称提供精确一次的传递语义,但读一下他们的细则很重要,大多数的宣称是误导性的(例如:他们没有说明很多场景:消费者和生产者会失败,多个消费者处理的情况,写入磁盘的数据可能会丢失)。

值得注意的是,这个问题可以被分为发送消息时的持久化保证和消息消息时的保证两个部分。

生产者发送消息语义

Kafka的语义是直接了当的。当发送消息时我们有个消息“已提交”的概念。一旦被发布的消息“已提交”则其不会丢失,因为有多个分区复制了这条消息,总有一个会存活。下一节我们将详细讨论“已提交”消息、存活分区和一些故障的处理方式。现在让我们假设有一个完美的无丢失的borker(Kafka将自身服务称为broker),来尝试理解消费者和生产者见的保证。如果生产者尝试发送消息但遇到了网络错误,他无法确保这个错误发生在消息“已提交”前还是消息“已提交”后。这和使用自动生成的key插入数据到数据库的语义很相似。

在0.11.0.0版本之前,如果生产者没有收到标识消息“已提交”的响应,它没有选择只能重发消息。这提供了至少一次语义(如果请求已经成功处理,重发时消息又被写入了一次日志)。从0.11.0.0版本开始,Kafka生产者支持幂等性选项,这保证重新发送不会导致日志中消息重复。为了实现它,broker为每个生产者分配一个ID,生产者发送的抗重复消息使用一个序列数字。同样从0.11.0.0版本开始,通过使用类事物语义(例如:要么所有消息都成功写入要么一个都没有成功),生产者支持发送消息到多个主题分区。类事物语义的主要应用场景是Kafka主题的精确一次处理(详见下文)。

不是所有场景都需要强保证。对于延迟敏感的应用,我们允许生产者设置持久性级别。生产者可能表示它希望最多10ms内得到消息“已提交”响应。但生产者同样可以指定它希望进行完全异步发送,或者希望一直等到broker leader收到消息(但不等待所有broker follower收到消息)。

消费者接收消息语义

现在让我们从消费者的视角来描述语义。所有复制有完全一致的日志及其偏移量。消费者控制其在日志中的位置。如果消费者从不会宕机它可以将位置存储在内存,但如果消费者失败了,我们希望主题分区能够被其他进程接管,新进程需要选择一个合适的位置开始处理日志。让我们假设消费者已经读取了一些消息,有以下可选方案来处理消息和更新问题:

  • 它可以先读取消息并保存位置到日志,最后处理消息。这种场景下消费者进程崩溃可能发生在保存位置后,保存处理输出结果前。此时接管进程会从保存问题启动,然而此位置之前的一些消息还没有被处理。由于消费失败的消息不会再被处理,这符合“最多一次”语义。
  • 它可以先读取消息、处理消息、最后再保存位置。这种场景下消费者进程崩溃可能发生在处理消息后保存位置前。此时新的接管进程最先接收的一些消息已经被处理过。在这种消费者失败场景下符合“最少一次”语义。在很多场景下,消息有一个主键,因此是幂等性的(接收同样的消息两次,但只会用相同的数据覆盖之前的记录)。

精确一次

现在你怎么看待“精确一次”语义(这真的是你实际想要的)?当从Kafka主题消费并生产到另一个主题(Kafka流应用这样做),我们可以利用上文提及的0.11.0.0版本带来的生产者事物功能。消费者位置在主体中作为一个消息存储,因此我们可以在已接收已处理数据的输出主题相同的事物中将偏移量写入Kafka。如果事物异常退出,基于隔离级别,消费者位置被还原到老位置,同时向输出主题发送的已生产的数据也将对下游消费者不可见。

  • 默认隔离级别是读未提交(read_uncommitted),所有消息都对消费者可见即使他们所在的事物异常退出。
  • 在读已提交(read_committed)级别,消费者只能看到已提交事物中的消息(还有不在事物中的消息)。

当写到外部系统时,关键在于协调消费者位置和实际已存储的输出。经典的方式是在消费者位置存储和消费者输出存储间进行两阶段提交。其实让消费者在输出位置一起存储偏移量可以让方案更简单和通用。这种方案更好,因为消费者写入的很多输出系统可能不支持两段式提交。例如,使用Kafka Connect存储数据和偏移量到HDFS,这将能保证数据和偏移量同时更新或者同时不更新。我们遵循和其他很多数据系统(需要强语义或者消息没有具有抗重复能力的主键时)类似的模式。

在Kafka流应用中,Kafka有效的支持精确一次传递;当通过Kafka主题传输和处理数据时,通常使用消费者/生产者事物可以提供精确一次传递。对于其他目的系统,要实现精确一次传递通常需要在系统间协调处理,Kafka提供的偏移量让协调更可行(参考:Kafka Connect)。另外,Kafka默认保证至少一次传递,并允许用户通过禁用生产者发送重试和消费者先记录偏移量再处理数据来实现最多一次传递。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值