TT Lab
はじめる
学ぶ 学習パス コース

ICA — Istio認定アソシエイト

復元力の設定値を見積もる

TT Labで続きを見る

目標

リトライ・タイムアウト・サーキットブレーカー・障害注入・ミラーリングを自分で書きながら、各値がお互いにどんな制約をかけるのかを理解します。

なぜ重要なのか

レジリエンスの設定は、コピーしてきてもたいていは動作しないか、さらに悪いことに、障害を増幅させます。リトライを呼び出しチェーンのすべての階層にかけると、3段のチェーンでは最悪の場合に9倍、4段なら27倍のリクエストが、最も内側のサービスに集中します。すでに死にかけているサービスに対して、リトライがとどめの一撃になる構造です。

タイムアウトも同じです。timeoutはリトライとbackoffを含む全体の予算で、perTryTimeoutは各試行の上限です。速い失敗であれば、全体の予算が試行ごとの上限の合計より小さくても、リトライできます。逆に、1つの試行が全体の予算を使い切ると、次の試行が始まらないことがあります。このラボの3秒/1秒/追加2回は、設定を書くための値であり、3つの試行がそれぞれ1秒ずつ必ず実行されるという保証ではありません。実際の回数は、失敗の条件と応答時間、backoffを一緒に観測する必要があります。外側の呼び出し元が待つのをやめても、内側の業務処理が取り消されるという保証はないので、すでに処理された書き込みを再実行しないように、重複防止とキャンセルの伝播を別に設計します。

サーキットブレーカーは、値が大きすぎると事実上切れているのと同じで、小さすぎると平常時にも503が出ます。そのため、実測の同時実行数を基準に算定し、maxEjectionPercentで安全弁を置きます。このラボは、その感覚をマニフェストに移す訓練です。

Kubernetesの基本リソースは実際にapplyし、Istio CRDは/root/ica-resilience/の下にファイルとして作成します。kwokベースの設計ラボなので、実際のEnvoyのHTTP応答・リトライの回数・業務の重複処理を、ここで検証したものとして扱わないでください。

ステップ

  1. ネームスペースica-resilienceを作成し、ラベルistio-injection=enabledを付けてください。
  2. ネームスペースica-resilienceに、Deployment inventoryをレプリカ3つでデプロイしてください。Podのラベルはapp=inventory、イメージはnginx:1.27-alpineです。
  3. 同じネームスペースにServiceを2つ作成してください。inventoryとinventory-canaryで、どちらもポート8080、ポート名httpです。inventoryのselectorはapp=inventoryです。
  4. /root/ica-resilience/vs-inventory-retry.yamlにVirtualServiceを作成してください。spec.hosts[0]はinventory.ica-resilience.svc.cluster.localで、httpルールにtimeout: 3s、retries.attempts: 2、retries.perTryTimeout: 1sを指定し、retries.retryOnには5xxとconnect-failureを含めてください。
  5. /root/ica-resilience/vs-inventory-fault.yamlにVirtualServiceを作成してください。ルールは2つです。最初のルールは、ヘッダーx-chaos-testがtrueのリクエストにだけ適用され、fault.delay.fixedDelay: 3s/fault.delay.percentage.value: 50/fault.abort.httpStatus: 503/fault.abort.percentage.value: 10を持ちます。2番目のルールは、matchもfaultもなく、ただルーティングするだけです。
  6. /root/ica-resilience/dr-inventory.yamlにDestinationRuleを作成してください。spec.hostはinventory.ica-resilience.svc.cluster.localで、trafficPolicyの下に、outlierDetection(consecutive5xxErrors 5、interval 10s、baseEjectionTime 30s、maxEjectionPercent 50)と、connectionPool(tcp.maxConnections 100、http.http1MaxPendingRequests 50)を置きます。
  7. /root/ica-resilience/vs-inventory-mirror.yamlにVirtualServiceを作成してください。inventory.ica-resilience.svc.cluster.localへ100%ルーティングしながら、inventory-canary.ica-resilience.svc.cluster.localへ20%ミラーリングし、全体のtimeoutは5sにします。

参考

ラボ用のネームスペースの準備

ネームスペースica-resilienceを作成し、ラベルistio-injection=enabledを付けてください。

前のラボと同じ方法です。自動注入のラベルを忘れないでください。

インスタンス3つのDeploymentをデプロイする

ネームスペースica-resilienceに、Deployment inventoryをレプリカ3つでデプロイしてください。Podのラベルはapp=inventory、イメージはnginx:1.27-alpineです。

outlierDetectionのmaxEjectionPercentを体感するには、インスタンスが複数ある必要があります。PodがReadyになるまで待ってから、採点してください。

本番用のServiceとカナリア用のServiceを作成する

同じネームスペースにServiceを2つ作成してください。inventoryとinventory-canaryで、どちらもポート8080、ポート名httpです。inventoryのselectorはapp=inventoryです。

ミラーリングの対象は、別のServiceにしておくほうが安全です。2つのServiceとも、ポート名をプロトコルが分かるように付けてください。

タイムアウトとリトライの関係を合わせる

/root/ica-resilience/vs-inventory-retry.yamlにVirtualServiceを作成してください。spec.hosts[0]はinventory.ica-resilience.svc.cluster.localで、httpルールにtimeout: 3s、retries.attempts: 2、retries.perTryTimeout: 1sを指定し、retries.retryOnには5xxとconnect-failureを含めてください。

timeoutは、リトライを含む全体のデッドラインです。perTryTimeout x (attempts + 1)がtimeoutを超えると、リトライが実行されないことがあります。retryOnには、リクエストが届く前に失敗した場合も含めてください。

ヘッダーでゲートした障害注入

/root/ica-resilience/vs-inventory-fault.yamlにVirtualServiceを作成してください。ルールは2つです。最初のルールは、ヘッダーx-chaos-testがtrueのリクエストにだけ適用され、fault.delay.fixedDelay: 3s/fault.delay.percentage.value: 50/fault.abort.httpStatus: 503/fault.abort.percentage.value: 10を持ちます。2番目のルールは、matchもfaultもなく、ただルーティングするだけです。

本番のクラスターで、全トラフィックにfaultをかけることは、カオステストではなく障害です。マッチするルールと、通常のトラフィック用のルールを分けて、faultはマッチした側にだけ置いてください。

サーキットブレーカーの上限を決める

/root/ica-resilience/dr-inventory.yamlにDestinationRuleを作成してください。spec.hostはinventory.ica-resilience.svc.cluster.localで、trafficPolicyの下に、outlierDetection(consecutive5xxErrors 5、interval 10s、baseEjectionTime 30s、maxEjectionPercent 50)と、connectionPool(tcp.maxConnections 100、http.http1MaxPendingRequests 50)を置いてください。

connectionPoolとoutlierDetectionは、同じDestinationRuleのtrafficPolicyの下に並んで入ります。インスタンスが3つのときに、同時排除の割合を100にすると、何が起きるかを考えてみてください。

シャドウトラフィックを流す

/root/ica-resilience/vs-inventory-mirror.yamlにVirtualServiceを作成してください。inventory.ica-resilience.svc.cluster.localへ100%ルーティングしながら、inventory-canary.ica-resilience.svc.cluster.localへ20%ミラーリングし、全体のtimeoutは5sにしてください。

ミラーリングは応答を捨てるので、実際のrouteは1つだけ置きます。ミラーの対象はステップ3で作ったカナリアのServiceで、割合は、mirrorの隣の別のフィールドで指定します。