Kafka 幂等性原理(单分区单会话):
producer的幂等性(重试引起的乱序和重复)
- 重复问题的解决:
- Kafka 增加了 pid 和 seq。Producer 中每个 RecordBatch 都有一个单调递增的 seq; Broker 上每个 topic 的 partition 也会维护 pid-seq 的映射,并且每 Commit 都会更新 lastSeq。
- recordBatch 到来时,broker 会先检查 RecordBatch 再保存数据: 如果 batch 中 baseSeq(第一条消息的 seq)比 Broker 维护的序号(lastSeq)大 1,则保 存数据,否则不保存。
- 乱序问题的解决: 假设我们有 5 个batch的 请求,batch1、batch2、batch3、batch4、batch5; 如果只有 batch2 ack failed,3、4、5 都保存了,那 2 将会随下次 batch 重发而造成重复。 可以通过降低吞吐的情况来保证乱序问题----设置 max.in.flight.requests.per.connection=1(producer netClient每一次发送的等待回复的请求数,默认是5)来解决乱序,但降低了系统吞吐。 新版本 kafka 设置 enable.idempotence=true(开启幂等) 后能够动态调整 max-in-flight-request。正常 情况下 max.in.flight.requests.per.connection 大于 1。当重试请求到来时,batch 会根据 seq 重新添加到队列的合适位置,并把 max.in.flight.requests.per.connection 设为 1,这样它前面的 batch 序号都比它小,只有前面的都发完了,才会继续发送。
Kafka的事务:
配置:
- 对于Producer,需要设置
transactional.id
属性,这个属性的作用下文会提到。设置了transactional.id
属性后,enable.idempotence
(幂等性)属性会自动设置为true。- 对于Consumer,需要设置
isolation.level = read_committed
,这样Consumer只会读取已经提交了事务的消息。另外,需要设置enable.auto.commit = false
来关闭自动提交Offset功能。
Kafka的事务主要包括三个功能:原子写操作,拒绝僵尸实例(Zombie fencing)和读事务消息。
- 本质是,将一组写操作(如果有)对应的消息与一组读操作(如果有)对应的Offset的更新进行同样的标记(Transaction Marker)来实现事务中涉及的所有读写操作同时对外可见或同时对外不可见。 Kafka只提供对Kafka本身的读写操作的事务性,不提供包含外部系统的事务性。
Kafka事务特性通过
transaction-id
属性来解决僵尸实例问题。所有具有相同transaction-id
的Producer都会被分配相同的pid,同时每一个Producer还会被分配一个递增的epoch。Kafka收到事务提交请求时,如果检查当前事务提交者的epoch不是最新的,那么就会拒绝该Producer的请求。从而达成拒绝僵尸实例的目标。
详情可以参考链接:www.jianshu.com/p/64c930654…
Kafka的数据有序性:
kafka是保证分区有序性的,不保证topic有序性;有强有序性要求情况: a. 有序性要求的数据写入同一个分区,可以通过key分流:或者单分区topic,牺牲吞吐量 b. 解决重试有序性问题:enable.idempotence=true(幂等性开启) 和 调高retries 并且调高delivery.time.out时间(等待回复的时间)