重複を記憶する場所はPodの外にある
一言でいうと
再試行を安全にするには、実行IDとビジネスIDを区別し、副作用を保存する境界で同じビジネスキーを一貫して処理する必要があります。
なぜ必要なのか
配送プログラムが、起動時にランダムなUUIDを作り、すでに処理したリクエストかどうかを照会するように変更されたとします。UUIDが衝突する確率は小さいですが、二重配送はそのままかもしれません。新しいPodが実行されるたびに新しいUUIDを作るからです。同じ注文の再試行が、別の業務のように見えてしまうのです。識別子が一意であるという性質と、同じ業務を同じものと見分けられるという性質は、別のものです。
Pod内の一時ファイルに処理の完了を書いておく方法も、再試行の境界を越えられないことがあります。Jobが新しいPodを作ったとき、前の実行のメモリやローカルファイルがそのまま引き継がれると仮定することはできません。ラボはこの違いを隠さないよう、各リクエストにPod UIDを記録しながら、配送の重複の判断には別のビジネスキーを使います。
どう動くのか
学習用のリクエストには、4つの値があります。case_idは独立した実験の業務範囲で、work_idはその範囲の論理的な注文です。pod_uidはリクエストを送った実行を追跡し、modeは比較群と冪等処理を区別します。同じ業務を再実行するときは、case_idとwork_idを維持し、新しいPod UIDは異なる値になる必要があります。実際のサービスでは、アカウント・テナント・作業の種類を含むキーの範囲と、再利用のポリシーを別に決める必要があります。
元帳は、リクエストの試行と配送の副作用を別々の表で管理します。リクエストが2回入ってきても、配送の結果は1回だけ作れます。同じキーをもう一度受け取ると、最初の配送番号を返し、新しいリクエストの試行は引き続き記録します。そのおかげで、重複を排除したからといって、観測情報まで消してしまうことはありません。
核心は、照会と保存のあいだの競合です。2つのリクエストがほぼ同時に届き、それぞれが「ない」と読んだあとで新しい配送を保存すると、重複が生じることがあります。ラボの元帳は、SQLiteの書き込みトランザクションの中でキーの照会と挿入を処理し、冪等キーには一意制約を付けます。クライアントのif文1つで、並行処理の安全性を代わりにはしません。エラーが起きたら、そのトランザクションは成功した配送として報告しません。
실행 추적: Pod A → 요청 1
Pod B → 요청 2
업무 판정: 같은 업무 키 → 같은 배송 번호
これを、任意の厳密に1回の配信保証と呼ぶことはしません。この例は、元帳の内部で、1種類の行の挿入を1回にまとめています。実際の宅配業者・メールサーバー・別のDBまで、元帳のトランザクションに自動的に参加するわけではありません。外部システムの冪等API、結果の照会、アウトボックス、調整といった追加の契約が必要になる場合があります。どのストレージの境界を保護したのかを、説明できなければなりません。
現場での姿
運用担当者が、完了したJobとは別の名前のJobを新しく作って、同じ注文を再実行することがあります。Job UIDを冪等キーに使うと、新しい実行は新しいキーになるため、以前の副作用を見分けられません。逆にビジネスキーを維持すれば、Kubernetesのオブジェクトが違っても、同じ結果を再利用できます。実行オブジェクトを消すことと、業務の処理履歴を消すことが別のライフサイクルである理由です。
すべてのリクエストを同じキーでまとめるのも間違いです。異なる注文まで同じ配送にまとまると、重複は減りましたが、正常な業務を失いました。テストは、同じキーの繰り返しだけでなく、異なるキーがそれぞれ処理されるかも確認する必要があります。同じキーなのに本文の内容が変わる場合を許可するのか拒否するのか、キーをどのくらいの期間保管するのかも、実際の契約の一部です。このラボの小さなリクエストモデルには、住所・品目がないので、そのような衝突のポリシーを実装したと主張することはしません。
CronJobは、決まった時刻にJobを作る役割で、冪等な元帳の役割を代わりに果たすものではありません。concurrencyPolicyをForbidに決めても、同じCronJobが作ったJobの重複を制限する設定であって、外部の元帳に対する重複処理の契約ではありません。別のCronJob、手動のJob、運用担当者の再実行の経路まで、ビジネスキーがつながっているかを別に点検する必要があります。
ストレージの存続性も区別します。実験の元帳は、別のPodのemptyDirの中にあるSQLiteにあります。作業Podの入れ替えには影響されませんが、元帳のPod自体が入れ替わるとデータが消えます。そのため、元帳のPod UIDとプロセスのboot_idが変わっていないかを確認します。この構成で、永続的な保存・マルチノードの高可用性・災害復旧まで解決したわけではありません。
次のラボですること
同じ保存後の失敗を維持したまま、元帳の冪等処理を有効にします。リクエスト2回と配送1件を一緒に確認し、別のJobで同じ業務をもう一度実行しても配送番号が維持されるかを確認します。最後に、元帳の試行の一覧を消したり、成功の表示だけを読んだりせず、異なる業務は残り、重複した業務だけがまとめられたかを説明してください。
公式ドキュメントと適用範囲
Kubernetesの実行の特性と、アプリケーションの保存の契約をつなぐ教材です。冪等性を、ファイル1つの有無や、Jobの成功条件に縮小することはしません。