我正在查看文档,了解到我们可以启用idempotence=true
幂等:幂等生产者对一个 制片人针对一个主题。基本上每条消息都发送 有石匠人的担保,如果有 错误
那么,如果我们已经有了幂等性,那为什么我们要在Kafka Stream中一次只需要另一个属性呢?幂等与完全一次之间究竟有什么区别
为什么普通Kafka Producer中无法使用一次精确属性?
答案 0 :(得分:12)
Kafka流从端到端的角度提供一次精确的语义(从一个主题进行消费,处理该消息,然后生成另一个主题)。但是,您仅提及了生产者的幂等属性。那只是整个图片的一小部分。
让我改一下这个问题:
为什么我们需要在消费者端实现一次准确的投放语义 虽然我们已经保证在 生产者方面?
答案::由于一次准确的传递语义不仅在生产步骤中,而且在处理的整个流程中也是如此。为了在语义上实现一次准确交付,必须满足生产和消费的一些条件。
这是一般情况:进程A产生到主题T的消息。同时,进程B尝试使用主题T的消息。我们要确保进程B永远不会处理一条消息两次。
生产者部分:我们必须确保生产者从不产生两次消息。我们可以使用Kafka Idempotent Producer
消费部分: 这是消费者的基本工作流程:
以上步骤只是一条快乐的路。现实中出现了很多问题。
因为可能会发生很多问题,所以作业的执行和提交偏移必须是 atomic (原子的),以确保在消费者端实现一次准确的交付语义。这并不意味着我们不能,但是要确保一次准确的交付语义就需要付出很多努力。 Kafka Stream支持工程师的工作。
请注意::Kafka Stream提供“一次精确的流处理”。它是指从一个主题进行消费,在Kafka主题中实现中间状态并产生一个状态。如果我们的应用程序依赖于其他一些外部服务(数据库,服务...),则必须确保我们的外部依赖关系可以保证在这种情况下仅发生一次。
TL,DR:一次,要实现全流程,需要生产者和消费者之间的合作。
参考:
答案 1 :(得分:5)
在分布式环境中,故障是很常见的情况,可以随时发生。在Kafka环境中,代理可能崩溃,网络故障,处理失败,发布消息时失败或无法使用消息等。 这些不同的情况导致了不同类型的数据丢失和重复。
故障场景
A(确认失败):生产者成功发布了消息,重试次数> 1,但由于失败而未能收到确认。在这种情况下,生产者将重试相同的消息,可能会导致重复消息。
B(生产者进程在批处理消息中失败):生产者发送了一批失败的消息,但发布的成功很少。在这种情况下,一旦生产者重新启动,它将再次批量重新发布所有消息,这将在Kafka中引入重复消息。
C(触发并忘记失败)生产者发布的消息,其中retry = 0(触发并忘记)。如果失败,发布的消息将不知道并发送下一条消息,这将导致消息丢失。
D(批处理消息中的消费者失败)消费者从Kafka接收到一批消息,并手动提交其偏移量(enable.auto.commit = false)。如果消费者在提交给Kafka之前失败,则下次消费者将再次使用相同的记录,这些记录将在消费者端复制副本。
完全一次语义
在这种情况下,即使生产者尝试重新发送消息,它也会导致 消息将被发布一次,并被消费者完全消费一次。
要在Kafka中实现精确一次语义,它使用以下3个属性
启用幂等(enable.idempotence = true)
等幂传递使生产者能够准确地将消息写入Kafka 一次在主题的生存期内转到主题的特定分区 一个生产者,没有数据丢失和每个分区的订单。
“”注意,启用幂等性要求MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION小于或等于5,RETRIES_CONFIG大于0且ACKS_CONFIG为'all'。如果用户未明确设置这些值,则将如果设置了不兼容的值,将抛出ConfigException“
为了实现幂等性,Kafka在生成消息时使用唯一的ID(称为产品ID或PID和序列号)。生产者在发布的每个消息上保持递增的序列号,这些消息具有唯一的PID。代理始终将当前序列号与前一个序列号进行比较,如果新序列号不比上一个序列号大+1,则它会拒绝,这会避免重复;如果消息中丢失了更大的序列号,则会拒绝同时显示
在失败的情况下,代理将序列号与前一个序列号进行比较,如果序列不增加,+ 1将拒绝该消息。
交易(隔离级别)
交易使我们能够自动更新多个主题分区中的数据。事务中包含的所有记录都将被成功保存,或者没有保存成功,它允许您将同一个事务中的消费者补偿与已处理的数据一起提交,从而允许端到端的一次精确语义
生产者无需等待将消息写入kafka,其中生产者使用beginTransaction,commitTransaction和abortTransaction(如果失败) 消费者使用隔离级别,即read_committed或read_uncommitted
如果具有isolation.level = read_committed的使用者到达了尚未完成的事务的控制消息,则它将直到该生产者提交或中止该事务或发生事务超时之前,不会再从该分区传递任何消息。事务超时由生产者使用配置transaction.timeout.ms(默认为1分钟)来确定。
生产者和消费者完全相同
在正常情况下,我们的生产者和消费者是分开的。生产者必须具有幂等性并同时管理事务,以便消费者可以使用isolation.level读取read_committed以使整个过程成为原子操作。 这样可以确保生产者将始终与源系统同步。即使生产者崩溃或事务中止,它也始终是一致的,并且一次将消息或一批消息发布为一个单元。
同一使用者将一次接收消息或一批消息。
在精确一次语义生成器和消费者中将出现为 原子操作,它将作为一个单元运行。要么发布并 一次被消耗掉或中止。
在Kafka流中恰好一次
Kafka Stream使用来自主题A的消息,处理该消息并将其发布到主题B,一旦发布,请使用commit(commit主要在后台运行)将所有状态存储数据刷新到磁盘。
Kafka Stream中的“一次”是“读取-处理-写入”模式,可确保将这些操作视为原子操作。由于Kafka Stream可以满足生产者,消费者和交易的需求,因此Kafka Stream都带有特殊的参数processing.guarantee,它可以完全地_once或at_least_once,使得不单独处理所有参数变得容易。
Kafka Streams原子地更新消费者补偿,本地状态存储, 状态存储changelog主题和生产以输出所有主题 一起。如果这些步骤中的任何一个失败,则所有更改都是 回滚。
processing.guarantee:完全_一次自动提供以下参数,您无需明确设置