Exactly Onceとmax.in.flightについて
max.in.flightが>1でもIdempotent Producerが機能する件について
はじめに
メッセージブローカー界隈でのデリバリー保証はAt Least Once (必ず送信するが1度以上送信する可能性がある) というのが常識であり、データを受け取るConsumer側で冪等性を保証する必要がありました。そのExactly Once SemantisがKafkaでサポートされた時には多くの反響を呼びましたが、この設定は最近DefaultでOnになる程Kafkaコミュニティでは広く利用されています。
ただこのエンハンスメントにも制限がありました。この制限は後日、ひっそりと一つのPRによって解消されています。話題には上りませんでしたが、この機能が広く利用される上では非常に重要なエンハンスメントでした。
Exactly Once Semantics
Kafka初期において最も注目を集めたエンハンスメントの一つにKIP-98 - Exactly Once Delivery and Transactional Messaging があります。「メッセージ基盤においてExactly Onceは不可能」という二人の将軍問題 観点からの懐疑的な意見も多く議論を呼びました。そもそもKafkaが唱えるExactly Onceのスコープは何か、そして何がその前提となっているのかについてはKafka初期開発者であるネハさんを始めとして具体的な説明もたくさんなされています。1
実際のKIPに記載されている設定条件は以下で、これらも同様に適切に設定しない限りはenable.idempotency=true
と設定してもProducerの冪等性を確保する保証はないと記載されています (仮にIdempotent Producerとして動いてPIDに値が設定されているとしても)。
ack=all
retries > 1
max.inflight.requests.per.connection=1
必ずISRへの同期が完了し、エラー時にはリトライする様にし、かつProducerからの並列送信は許容しない、という条件です。理には適っています。
KAFKA-5494
KAFKA-5494: enable idempotence with max.in.flight… このPRではKIP-98実装における課題の説明と、それに対する解決策が記載されています。具体的には2つの課題への対応が纏まったPRとなっており、結果としてmax.in.flight.requests.per.connectionが1である制限を最大5まで増やす対応となっています。2
対応としてのポイントは、Brokerとの通信途絶時のProducer側 (Client) のシーケンス番号の採番ルールです。送信エラーとなった場合にはシーケンス番号を採番し直す事により処理を自動復旧すること、また再採番の前に送信処理中のバッチが全て処理済みである確認等が考慮されています。3
おわりに
KIPではなくPRとして実装されたこの変更ですが、シーケンス例外が出た際に事後復旧出来るようになる事、max.in.flightを1より大きく指定できる事、より広くIdempotent Producerを利用する上で重要な改善が含まれています。