kafka--基础知识点--5.2--producer幂等性

本文详细介绍了Kafka的幂等性producer和事务producer,这两种机制用于确保消息的精确一次性处理。幂等性producer保证单分区、单会话的幂等性,而事务producer则能实现跨分区、跨会话的幂等性,但性能相对较差。启用幂等性需设置`enable.idempotence=true`,事务producer则需要`enable.idempotence=true`和`transactional.id`。消费者在读取事务Producer消息时,需设置isolation.level参数来决定是否只读已提交事务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 概念

Kafka 的幂等性确保生产者重复发送相同消息时,broker的topic的分区中只会保存一份。此特性通过生产者配置实现,与 Broker 无关。

2 生产者端配置

关键参数:enable.idempotence,默认值是false,开启幂等性时需显式设置为true

producer幂等性配置如下:

from confluent_kafka import Producer

producer_config = {
    'bootstrap.servers': 'localhost:9092',
    'enable.idempotence': True,  # 启用幂等性
    'acks': 'all',               # 必须配合 acks=all 使用
    'retries': 5,                 # 重试次数
    'client.id': 'idempotent-producer'
}

producer = Producer(producer_config)

3 Broker 端要求

版本兼容性:Kafka 0.11.0.0 及以上版本支持幂等性。
无需额外配置:Broker 端无需修改 server.properties,只需确保版本兼容。

4 原理

我们在客户端参数显示设置enable.idempotence=true就会开启生产者幂等消息传递

1 每条消息都有一个主键,这个主键由 <PID, Partition, SeqNumber>组成。

  • PID:ProducerID,每个生产者启动时,Kafka 都会给它分配一个 ID,ProducerID 是生产者的唯一标识,PID会被事务协调器保存到__transaction_state主题中[即使客户端只启用幂等性没有启用事务,事务协调器也会给生产者分配一个PID并保持到__transaction_state主题中]。。
  • Partition:消息需要发往的分区号。
  • SeqNumber:生产者,他会记录自己所发送的消息,给他们分配一个自增的 ID,这个 ID 就是 SeqNumber,是该消息的唯一标识,每发送一条消息,序列号加 1。

2 对于主键相同的数据,kafka 是不会重复持久化的,它只会接收一条。

  • broker端会给每一对<PID,分区>维护一个序列号,对于收到的每一条消息,只有当它的序列号的值(SN_new)正好比broker端中维护的对应序列号的值(SN_old)大1,broker才会接收该消息。如果 SN_new < SN_old + 1,说明消息被重复写入,broker会将该消息丢弃。否则,说明中间有数据尚未写入,暗示可能有消息丢失,对应生产者会抛出 OutOfOrderSequenceException 异常

注意:序列号实现幂等只是针对每一对<PID,分区>,即Kafka的幂等性只能保证单个生产者会话(session)中单分区的消息不重复;当kafka 挂掉,重新给生产者分配了 PID,还是有可能产生重复的数据

为什么说幂等性只能保证单会话,单分区消息不重复?[仅是个人理解,不一定正确]

  • 单会话:当broker收到消息后,如果生产者崩溃了,生产者重启后,会冲洗分配给生产者一个pid,而不是之前的那一个,序列号也会从0开始,broker会认为是另一条消息,发生了同分消息重复,因此幂等性只能保证单会话不重复;
  • 单分区:当broker收到消息后,由于网络波动,生产者没有收到来自broker的确认消息,会重复发送,此时若发生以下几种情况,都可能导致跨分区消息重复,因此只能幂等性只能保证单分区不重复
    • 分区数变化:例如,主题分区数增加,导致消息被重新分配到新分区。
    • 键的哈希值改变:若消息带有键(key),且重试时键的哈希值因某些原因改变(如键本身被修改),可能导致分区分配不同。
    • 自定义分区器逻辑:若使用自定义分区器(如轮询策略),重试时可能因分区顺序改变而发送到不同分区。

5 关键验证步骤

1. 生产者日志验证

  • 启用调试日志:在生产者配置中添加 debug='producer'

    from confluent_kafka import Producer
     
    # 生产者配置
    producer_config = {
        'bootstrap.servers': 'localhost:9092',  # Kafka Broker 地址
        'debug': 'producer',                    # 启用生产者调试日志
        # 其他配置(可选)
        'acks': 'all',                          # 消息确认机制
        'retries': 3                            # 重试次数
    }
     
    # 创建生产者实例
    producer = Producer(producer_config)
     
    # 发送消息(示例)
    producer.produce('my_topic', key='key', value='message')
    producer.flush()
    

    关键说明:
    debug 参数:设置为 ‘producer’ 会输出生产者相关的调试日志(如消息发送、分区选择、网络交互等)。
    日志输出:调试日志默认输出到 stderr,可通过 Python 的 logging 模块重定向到文件或其他处理器。
    多组件调试:若需同时调试多个组件(如 Broker、Topic),可用逗号分隔:debug=‘producer,broker,topic,network’。[没验证过,具体用时可以去查一下相关资料]

  • 观察日志

    [2025-07-19 10:00:00,000] DEBUG Setting producer IDEMPOTENT (kafka.producer.KafkaProducer)
    

2. Broker 日志验证

  • 检查去重日志
    [2025-07-19 10:00:01,000] INFO Received message with PID=12345, Partition=0, SeqNumber=1 (kafka.broker.LogManager)
    [2025-07-19 10:00:02,000] WARN Duplicate message detected for PID=12345, Partition=0, SeqNumber=1 (kafka.broker.LogManager)
    

    3. 消费者测试

  • 模拟重试
    1. 发送消息后,立即断开生产者网络。
    2. 生产者重试发送相同消息。
    3. 消费者确认仅接收一次消息。

补充:
max.in.flight.requests.per.connection 的关联:
启用幂等性后,Kafka 会自动将 max.in.flight.requests.per.connection 设为 1,以确保消息顺序。若需更高并发,可显式设置该参数为更大值(如 5),但可能破坏顺序保证。

max.in.flight.requests.per.connection 是 Kafka 生产者客户端配置参数,用于控制生产者与单个 Broker 连接中未确认请求的最大数量。简单来说,它限制了生产者在等待之前发送的消息确认(ACK)时,可以同时向同一个 Broker 发送的未完成请求数量。

producer_config['max.in.flight.requests.per.connection'] = 5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值