[代码重构](master): kafka 幂等生产者和事务生产者是一回事吗

2022年9月19日13:56:55
master
土豆兄弟 2 years ago
parent 996fb6a09c
commit 76964434c7

@ -641,6 +641,71 @@ Properties props = new Properties ();
当然这只是软件层面的“长连接”机制,由于 Kafka 创建的这些 Socket 连接都开启了 keepalive因此 keepalive 探活机制还是会遵守的。 当然这只是软件层面的“长连接”机制,由于 Kafka 创建的这些 Socket 连接都开启了 keepalive因此 keepalive 探活机制还是会遵守的。
- 在第二种方式中TCP 连接是在 Broker 端被关闭的,但其实这个 TCP 连接的发起方是客户端,因此在 TCP 看来,这属于被动关闭的场景,即 passive close。被动关闭的后果就是会产生大量的 CLOSE_WAIT 连接,因此 Producer 端或 Client 端没有机会显式地观测到此连接已被中断。 - 在第二种方式中TCP 连接是在 Broker 端被关闭的,但其实这个 TCP 连接的发起方是客户端,因此在 TCP 看来,这属于被动关闭的场景,即 passive close。被动关闭的后果就是会产生大量的 CLOSE_WAIT 连接,因此 Producer 端或 Client 端没有机会显式地观测到此连接已被中断。
### 2.6 幂等生产者和事务生产者是一回事吗?
- Kafka 消息交付可靠性保障以及精确处理一次语义的实现。
- 所谓的消息交付可靠性保障,**是指 Kafka 对 Producer 和 Consumer 要处理的消息提供什么样的承诺**。常见的承诺有以下三种:
- 最多一次at most once消息可能会丢失但绝不会被重复发送。
- 至少一次at least once消息不会丢失但有可能被重复发送。
- 精确一次exactly once消息不会丢失也不会被重复发送。
- 目前Kafka **默认提供的交付可靠性保障是第二种**,即至少一次。
- Kafka 也可以提供最多一次交付保障,**只需要让 Producer 禁止重试即可**。这样一来,消息要么写入成功,要么写入失败,但绝不会重复发送。我们通常不会希望出现消息丢失的情况,但一些场景里偶发的消息丢失其实是被允许的,相反,消息重复是绝对要避免的。此时,使用最多一次交付保障就是最恰当的。
- 那么问题来了Kafka 是怎么做到精确一次的呢?简单来说,这是通过两种机制:**幂等性Idempotence和事务Transaction**。
- 什么是幂等性Idempotence
- 幂等性有很多好处,其最大的优势在于**我们可以安全地重试任何幂等性操作,反正它们也不会破坏我们的系统状态**。如果是非幂等性操作,我们还需要担心某些操作执行多次对状态的影响,但对于幂等性操作而言,我们根本无需担心此事。
- 幂等性 Producer
- 在 Kafka 中Producer **默认不是幂等性的**,但我们可以创建幂等性 Producer。它其实是 **0.11.0.0 版本引入的新功能**
- 在此之前Kafka 向分区发送数据时,可能会出现同一条消息被发送了多次,导致消息重复的情况。在 0.11 之后,指定 Producer 幂等性的方法很简单,仅需要设置一个参数即可
- **props.put(“enable.idempotence”, ture)**,或 **props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG true)**
- enable.idempotence 被设置成 true 后Producer **自动升级成幂等性 Producer**,其他所有的代码逻辑都不需要改变。
- **kafka 自动帮你做消息的重复去重**。底层具体的原理很简单,就是经典的用空间去换时间的优化思路,即在 Broker 端多保存一些字段。当 Producer 发送了具有相同字段值的消息后Broker 能够自动知晓这些消息已经重复了,于是可以在后台默默地把它们“丢弃”掉。
- 必须要了解幂等性 Producer 的作用范围
- 首先,它只能保证**单分区上的幂等性**,即一个幂等性 Producer 能够保证某个主题的一个分区上不出现重复消息,它无法实现多个分区的幂等性。
- 其次,它只能实现**单会话上的幂等性**,不能实现跨会话的幂等性。这里的会话,你可以理解为 Producer 进程的一次运行。当你重启了 Producer 进程之后,这种幂等性保证就丧失了。
- 如果我想实现多分区以及多会话上的消息无重复,应该怎么做呢?答案就是**事务transaction或者依赖事务型 Producer**。这也是幂等性 Producer 和事务型 Producer 的**最大区别**
- 事务
- 经典的 ACID即原子性Atomicity、一致性 (Consistency)、隔离性 (Isolation) 和持久性 (Durability)。
- 隔离性表明并发执行的事务彼此相互隔离,互不影响。
- Kafka 自 **0.11 版本开始也提供了对事务的支持**,目前主要是在 read committed 隔离级别上做事情。它能保证多条消息原子性地写入到目标分区,同时也能保证 Consumer 只能看到事务成功提交的消息。
- 事务型 Producer
- 事务型 Producer 能够保证将消息原子性地写入到多个分区中。这批消息要么全部写入成功,要么全部失败。另外,事务型 Producer 也不惧进程的重启。Producer 重启回来后Kafka 依然保证它们发送消息的精确一次处理。
- 设置事务型 Producer 的方法也很简单,满足两个要求即可:
- 和幂等性 Producer 一样,开启 **enable.idempotence = true**
- **设置 Producer 端参数 transctional. id**。最好为其设置一个有意义的名字。
- 此外,你还需要在 Producer 代码中做一些调整,如这段代码所示:
```java
producer.initTransactions();
try {
producer.beginTransaction();
producer.send(record1);
producer.send(record2);
producer.commitTransaction();
} catch (KafkaException e) {
producer.abortTransaction();
}
```
- 和普通 Producer 代码相比,事务型 Producer 的显著特点是调用了一些事务 API如 initTransaction、beginTransaction、commitTransaction 和 abortTransaction它们分别对应事务的初始化、事务开始、事务提交以及事务终止。
- 这段代码能够保证 Record1 和 Record2 被当作一个事务统一提交到 Kafka要么它们全部提交成功要么全部写入失败。实际上即使写入失败Kafka 也会把它们写入到底层的日志中,也就是说 Consumer 还是会看到这些消息。
因此在 Consumer 端,读取事务型 Producer 发送的消息也是需要一些变更的。
- 修改起来也很简单,设置 isolation.level 参数的值即可。当前这个参数有两个取值:
- read_uncommitted这是默认值表明 Consumer 能够读取到 Kafka 写入的任何消息,不论事务型 Producer 提交事务还是终止事务,其写入的消息都可以读取。很显然,如果你用了事务型 Producer那么对应的 Consumer 就不要使用这个值。
- read_committed表明 Consumer 只会读取事务型 Producer 成功提交事务写入的消息。当然了,它也能看到非事务型 Producer 写入的所有消息。
- 比起幂等性 Producer事务型 Producer 的性能要更差,在实际使用过程中,我们需要仔细评估引入事务的开销,切不可无脑地启用事务。
- 补充
- 事务的使用场景
- 事务更多用在Kafka Streams中。如果要实现流处理中的精确一次语义事务是不可少的。
- 事务型 Producer 可以实现一组消息要么全部写入成功,要么全部失败,但是事务型 Producer 是具体怎么实现多分区以及多会话上的消息无重复的呢?
- 主要的机制是两阶段提交2PC。引入了事务协调器的组件帮助完成分布式事务
### 2.7 消费者组到底是什么?
## 3. Producer生产者 ## 3. Producer生产者

Loading…
Cancel
Save