如果你曾经使用过阿帕奇卡夫卡,你可能知道官方文件所记载的保证。我想集中讨论这一具体问题:
生产者发送到特定主题分区的消息将按其发送顺序追加。
在这篇文章中,我想向您展示文档的保证不再真实的情况,即使您使用的是默认配置。让我们首先回顾一下卡夫卡如何在内部保存数据。
工作原理
正如您在上面的图片中看到的,它来自文档,Kafka 使用的主题只是发布记录的”源”的名称。您还可以注意到,对于每个主题,Kafka 维护一个分区日志,在官方文档中将其描述为:
每个分区都是一个有序的、不可变的记录序列,这些记录被不断追加到 – 结构化提交日志中。
因此,从我们的观点来看,要记住的最重要的事情是 Kafka 保留分区内的消息顺序。
对于某些用例,从业务角度来看,保留消息的顺序可能非常重要。例如,假设您正在从事某种银行项目,您正在通过 Kafka 进行沟通。保持银行帐户中操作的正确顺序非常重要。
否则,如果消息将以错误的顺序使用,则应用程序的用户可能会在事务期间失败,因为取款消息将在包含存款的消息之前到达,并且无法处理交易。
你也可能喜欢:一个卡夫卡教程为大家,不管你的发展阶段。
基普-91生产者中的直观用户超时
前段时间,卡夫卡制作人实施方案有一个变化,名为:《生产者》中的直观用户超时。主要介绍此更改是为了将所有可用的发送超时设置包装成一个:delivery.timeout.ms。
但是,这个提议引入了另一个小的变化,它被记录为:将重试的默认值更改为MAX_INT建议文档中,这看起来不像是需要记住的重要内容1.0,因此这也影响了阿尔帕卡卡夫卡连接器自版本1.0。如果您正在仔细阅读 Apache Kafka 升级说明,您可以注意到整个更改被描述为:
正如我们在 KIP-91 中引入delivery.timeout.ms的那样,生产者重试配置的默认值已更改为 Integer.MAX_VALUE,该值为发送记录和从代理接收确认之间的总时间设置上限。默认情况下,传递超时设置为 2 分钟。
处理失败 = 重试机制
由于 Kafka 2.1.0 当消息不会由代理确认时,则默认情况下,生产者将再次重新发送消息,最多 2147483647 (MAX_INT) 时间或直到delivery.timeout.ms过期(默认情况下为 2 分钟),这是在基普-91。但是,在这种情况下,这并不重要。最重要的信息隐藏在重试参数的描述中:
允许在不设置 max.in.flight.s.s.per.connect 到 1 的情况下重试可能会更改记录的顺序,因为如果将两个批处理发送到单个分区,并且第一个批处理失败并重试,但第二个批处理成功,则第二批中的记录可能首先出现。
最大.in.flight.s.s.s.per.连接的默认值为 5。因此,正如您所料,在代理未确认记录时失败时,创建者可能会发送很可能以错误顺序存储的记录,这是 Kafka 制作者的正常行为,因此默认情况下,Kafka 不保证发送的消息由特定主题分区的生产者按其发送顺序追加。
总结
只需更改一个生产者设置max.in.flight.s.s.per.per.connect到 1,即可轻松修复此行为,但请注意,更改此属性可能会影响生产者吞吐量。您还可以设置enable.ideme_true,而无需减少 max.in.flight.s.s.per.connect,但您需要根据文档调整其他设置:
请注意,启用幂等要求 max.in.flight.s.per.per.连接小于或等于 5,重试大于 0,ack 必须为”all”。如果用户未显式设置这些值,则将选择适当的值。如果设置了不兼容的值,则将引发配置异常。
这将起作用,因为生产者如何实现幂等性的原因。在不过多地了解细节的情况下,有一个由制作者维护的序列号,该序列号会发送到 Kafka,每条消息都发送到,如果此序列号正好比最后一个序列号多 1 个,则消息将存储在 Kafka 中。
更多关于它是如何工作的,你可以阅读在亚当·沃斯基博客文章:卡夫卡的准确一次性处理真正意味着什么? .值得知道的是,当发生故障时,默认配置可能导致以错误的顺序生成消息,如果消息顺序对应用程序很重要,则可能会遇到很多麻烦,因为有人告诉您,您可以看到并不总是真实的。