Kafka 事务(Transactions)

前言

Kafka 事务(Transactions) 主要用于确保 生产者(Producer)消费者(Consumer) 在数据传输过程中保持 原子性一致性,避免出现脏读不完整的数据消费

 

一、Kafka 事务的作用

Kafka 的事务特性 保证了消息的 "Exactly-Once 语义(EOS)"。

  1. 避免部分提交数据(Partial Commit),如果 Producer 生产的消息部分写入,但发生故障,Kafka 事务可以确保这些消息要么全部可见,要么全部回滚。 

  2. 跨多个分区的原子性(Atomicity Across Partitions),Kafka 事务允许一次性写入多个 Topic 分区,保证这些分区数据要么全部提交,要么全部撤销。
  3. 保证消费者端的 “Exactly-Once” 语义,Kafka Consumer 可以使用事务隔离级别只消费已提交的事务消息,防止读取未提交的部分消息。

 

 二、Kafka 事务的实现

Kafka 事务依赖于 Producer 端的事务 ID(Transactional ID),Kafka 通过事务协调器(Transaction Coordinator)进行事务管理。

事务流程:

  1. Producer 初始化事务(Init Transaction),Producer 需要设置 事务 ID,Kafka 会为其分配一个 事务协调器(Transaction Coordinator)

  2.  Producer 开启事务(Begin Transaction),Producer 可以向 多个分区 发送消息。

  3. Producer 发送消息(Send Messages),事务期间,Producer 持续向 Kafka 发送数据(数据暂存)。

  4. Producer 提交事务(Commit Transaction),事务提交后,Kafka 保证所有消息对 Consumer 可见

  5. Producer 回滚事务(Abort Transaction),如果 Producer 发生异常,可以选择 回滚事务,Kafka 会丢弃这些未提交的数据

 

 三、代码实操

 生产者(Producer)端事务

Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG, "transaction-1"); // 设置事务 ID
props.put(ProducerConfig.ACKS_CONFIG, "all"); // 确保数据持久化
KafkaProducer<String, String> producer = new KafkaProducer<>(props);

// 初始化事务
producer.initTransactions();

try {
    producer.beginTransaction();  // 开始事务
    producer.send(new ProducerRecord<>("topicA", "key1", "value1"));
    producer.send(new ProducerRecord<>("topicB", "key2", "value2"));
    producer.commitTransaction(); // 提交事务
} catch (Exception e) {
    producer.abortTransaction();  // 发生异常,回滚事务
}
producer.close();
  • beginTransaction() 开启事务
  • commitTransaction() 提交事务
  • abortTransaction() 事务失败时回滚,防止数据不一致

 消费者(Consumer)端事务

 Kafka Consumer 开启事务隔离级别,只消费已提交的数据

Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "group1");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.ISOLATION_LEVEL_CONFIG, "read_committed"); // 只读取已提交的事务数据
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(Collections.singletonList("topicA"));

while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records) {
        System.out.println("Consumed: " + record.value());
    }
}
  • ISOLATION_LEVEL_CONFIG = "read_committed":确保 只消费已提交的事务数据,防止读取未提交的消息。

 

 四、事务 vs 幂等性

特性kafka幂等性(Idempotence)Kafka事务(Transactions)
作用避免Producer重复发送确保跨分区、跨批次的事务一致性
机制依赖Producer ID(PID)和序列号依赖事务ID+事务协调器
数据范围单分区多分分区
幂等性保证Exactly-Once语义(单分区)Exactly-Once语义(跨分区)

 

 

 

 

 

 

 

 

 五、Kafka 事务的限制

  • 仅支持 Kafka 自身事务,不能和 外部数据库(MySQL, PostgreSQL)事务联动。
  • 事务超时限制,Kafka 默认事务超时时间为 15 分钟,超时未提交会自动回滚。
  • 性能损耗,事务需要额外的协调器操作,比普通 Producer 有一定的开销。

 

总结

  • Kafka 事务 适用于 跨多个分区的 Exactly-Once 语义,确保数据一致性。

  • Producer 端事务 通过 事务 ID 和 事务协调器 保障数据的完整性。

  • Consumer 端事务 需要 read_committed 级别确保只消费已提交的消息。

  • Kafka 幂等性 适用于 单个分区的数据去重,而事务适用于 多个分区的原子提交。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值