応答は失敗したのに業務はコミット済み
目標
実際のIstioのリトライと業務記録を比較し、応答のタイムアウトやプロセスの終了が起きても、同一の業務の重複を防ぐトランザクションの境界を実装します。
なぜ重要なのか
200は業務が1回だけ行われた証明ではなく、504はロールバックの証明ではありません。同じ注文の送信の試行ごとに新しい業務キーを作ると、重複防止の仕組みも無力になります。逆に、内容が同じ別の注文をまとめてしまうのも、エラーです。このラボは、実際のメッシュでの合成のHTTP業務と、別のトランザクションコードの修正を一緒に扱います。受講生のコードの修正は、一時的なSQLiteのテストに適用されるものであり、HTTPサーバーのコードを自動で入れ替える機能ではありません。
ステップ
- python3 /opt/fixtures/ica-retry/runtime.py inventoryの出力の全体を、/root/ica-retry/inventory.jsonに保存します。namespaceはica-retryで、clientとupstreamの実際のプロキシが準備できている必要があります。
- /root/ica-retry/routes.yamlに、networking.istio.io/v1のVirtualService retry-labを作成します。namespaceはica-retry、hostsとすべての宛先はupstream.ica-retry.svc.cluster.local、ポートは8080です。最初のルートflakyは、/flaky・/naiveのexactの2つのmatch、timeout 1s、attempts 2、perTryTimeout 1s、retryOn '503'、retryIgnorePreviousHosts falseです。2番目のlostは、/lostのexact、timeout 500ms、attempts 0です。最後のcontrolは、matchなしで同じ宛先、attempts 0です。適用後にcollect retryを実行して、retry.jsonの実際の受信・業務の回数を比較します。
- 同じツールのcollect timeoutを実行します。timeout.jsonには、/lostのクライアントの504、サーバーのコミット済みの応答、同じキーで/chargeを呼び出した回収結果が、一緒に入っている必要があります。数値を自分で作って書いてはいけません。
- collect conflictでconflict.jsonを保存します。同じ業務キーで金額を100から200に変えたリクエストが409を受け取り、既存の業務の金額は100のまま残っているかを確認します。
- collect durabilityでdurability.jsonを保存します。ツールは、このVMの中のupstreamのPodだけを、実際に削除・再作成します。clientのUIDは同じで、upstreamのUIDとサーバーのinstanceは異なる必要があります。同じ業務キーと応答IDは、保持されている必要があります。
- /opt/fixtures/ica-retry/broken.pyを/root/ica-retry/transaction.pyにコピーして、chargeのデフォルトの実行にある、コミットが分かれている欠陥を直します。initialize・charge・Conflict、after-business・after-key・after-commitの強制終了の地点は維持します。コミット前は業務・キーともに0個、コミット後は両方とも1個が残り、リトライ後に業務は常に1個である必要があります。
- transaction_probe.py /root/ica-retry/transaction.py identityで、同じキーの同時リクエスト8個を確認します。新しい処理は1つである必要があり、同じキーでの顧客・金額の変更はConflict、JSONの順序の変更は同じ応答、別のキーの同じ内容は別の業務である必要があります。誤った金額と未知のフィールドは、ValueErrorで拒否します。
- /root/ica-retry/incident.jsonに、追加の試行2・最大の試行3・naiveの業務3・重複防止の業務1を記録します。timeout_means_rollbackとexternal_payment_exactly_onceはfalseです。changed_payload_statusは実際の衝突コード、durable_scopeはsame-vm-disk、atomic_scopeはsingle-sqlite-fileと書きます。先行する実際の観測もそのまま残して、最終の採点を受けます。
参考
- コマンドの例: python3 /opt/fixtures/ica-retry/runtime.py collect timeout。観測ファイルがあれば、既存の結果を保持します。新しいテストが必要なら、自分の観測ファイルを別の名前で保管してから実行してください。
- 最初にapplyしたポリシーは、Envoyに伝播する時間が必要です。collectがルートの不一致を報告したら、実際のproxy-config routesを確認してください。
- broken.pyは、コミットが分かれている事故を再現する、意図的な誤答です。採点は、受講生のファイルを直さず、一時的なDBで実行します。
- 負荷実験の成功比率や応答の速さそのものを、正解として覚えないでください。業務キーごとの状態を見ます。
- 同じVMのディスクの保持だけを扱います。VMの終了・電源の遮断・外部の決済のexactly-onceは保証しません。個人のデータや実際の決済情報を入れないでください。
実際のプロキシとPodのアイデンティティの記録
inventoryコマンドで、2つのPodのUIDを記録します。Runningの名前だけを見ず、実際のプロキシが準備できているかを確認してください。
3回の受信と3回の業務を区別する
routes.yamlを適用して、collect retryを実行してください。attemptsは追加の試行であり、/naiveと/flakyの業務の帳簿を別々に見ます。
504のあとの、すでにコミットされた業務の回収
/lostの500msの予算と、リトライなしの条件を確認してください。collect timeoutは、同じ業務キーで/chargeにもう一度尋ねます。
同じキーの別の金額の拒否
collect conflictの2つのリクエストは、業務キーが同じで、金額だけが違います。既存の業務と応答が保持されているかを確認してください。
Podを入れ替えても同じ業務の応答
collect durabilityは、このVMのupstreamだけを入れ替えます。PodのUIDとサーバーのinstanceが変わり、業務IDは同じである必要があります。
コミットが分かれている欠陥をコードで直す
broken.pyをtransaction.pyにコピーして読んでください。chargeのデフォルトの実行で、業務の書き込みと重複の記録の間に、コミットが挟まっていないかを探してください。
同時リクエストと別の業務の境界
同じキーの同時リクエストは1つにまとめ、別のキーの同一の内容は、別の業務として残します。内容の変更の拒否とJSONの順序も確認してください。
応答と業務を分けた事故のレポート
最大の試行数と、実際の業務への効果を区別し、保証の範囲を、単一のSQLiteファイル・同じVMのディスクに限定してください。