Apache Kafka消息传递精确正好一次的含义 | TechMyTalk


在分布式环境中,故障是很常见的情况,可以随时发生。在Kafka环境中,消息代理可能会崩溃,网络故障,处理故障,发布消息时失败或无法使用消息等。这些不同的情况导致了不同类型的数据丢失和重复。

失败场景

  • A(确认失败):  生产者成功发布了消息,但由于失败而未收到确认回执。在这种情况下,生产者将重试相同的消息,可能会引入重复消息。
  • B(生产者进程在批处理消息中失败):  生产者发送了一批失败的消息,但发布成功的很少。在这种情况下,一旦生产者重新启动,它将再次批量重新发布所有消息,这将在Kafka中引入重复消息。
  • C(  触发并忘记失败)生产者发布的消息,重试= 0(触发并忘记)。如果失败,发布的消息将不知道并继续发送下一条消息,这将导致上一条消息丢失。
  • D(批处理消息中的消费者失败)  消费者从Kafka接收到一批消息,并手动提交其偏移量(enable.auto.commit = false)。如果消费者在提交给Kafka之前失败,则下次消费者将再次使用相同的记录,这些记录将在消费者端复制副本。

精确一次语义
在这种情况下,即使生产者尝试重新发送消息,它也导致消息将被消费者发布和消费一次。
为了在Kafka中实现Exactly-Once语义,它使用以下3个属性:

  • enable.idempotence = true
  • MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5(生产者每次连接总是有一个飞行中请求)
  • isolated.level = read_committed

启用幂等(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将拒绝该消息。

事务(isolation.level)
事务使我们能够自动更新多个主题分区中的数据。事务中包含的所有记录都将被成功保存,或者没有保存成功,它允许您将同一个事务中的消费者补偿与已处理的数据一起提交,从而允许端到端的一次精确语义。
生产者不等待将消息写到kafka,生产者使用beginTransaction,commitTransaction和abortTransaction(如果发生故障),消费者使用isolate.level级别:要么是read_committed要么是read_uncommitted

  • read_committed:使用者将始终仅读取提交的数据。
  • read_uncommitted:以偏移顺序读取所有消息,而无需等待事务提交

如果具有Isolation.level = read_committed的使用者到达尚未完成的事务的控制消息,它将不会再从该分区传递任何消息,直到生产者提交或中止该事务或发生事务超时。事务超时由生产者使用配置transaction.timeout.ms(默认为1分钟)确定。

生产者和消费者中的确切时间
在正常情况下,生产者和消费者是分开的。生产者必须具有幂等性并同时管理事务,以便消费者可以使用isolation.level读取read_committed以使整个过程成为原子操作。这样可以确保生产者将始终与源系统同步。即使生产者崩溃或事务中止,它也始终是一致的,并且一次将消息或一批消息发布为一个单元。
同一用户一次将收到消息或一批消息。
在Exactly-Once中,语义生产者与消费者一起将作为原子操作出现,它将作为一个单元进行操作。要么发布一次就被消耗掉,要么中止。

在Kafka Stream中恰好一次
Kafka Stream消耗来自主题A的消息,处理并将消息发布到主题B,并在发布后使​​用commit(commit主要在后台运行)将所有状态存储数据刷新到磁盘。
在Kafka Stream中,一次完全是读取过程写入模式,可确保将这些操作视为原子操作。由于Kafka Stream可以满足生产者,消费者和交易的需求,因此Kafka Stream附带了特殊的参数processing.guarantee,它可以完全地_once或at_least_once使得不单独处理所有参数变得容易。
Kafka Streams原子地更新使用者偏移量,本地状态存储,状态存储changelog主题和生产,以一起输出所有主题。如果这些步骤中的任何一个失败,则所有更改都将回滚。
processing.guarantee:确切地提供一次以下参数,您无需明确设置

  1. isolated.level = read_committed
  2. enable.idempotence = true
  3. MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5