準備チェックと外れ値検出は別のものを見る
一言でいうと
Kubernetesは、Podが自分で報告する状態(readinessプローブ)でトラフィックを外します。メッシュの外れ値検出は、サイドカーが実際に受け取ったレスポンスで外します。readinessプローブは通るのにリクエストごとに500を返すPodは、前者の目には正常で、後者の目にだけ故障です。
なぜ必要なのか
readinessプローブは、普通/healthzのような軽いパスを見ます。ところが障害は、そのパスの外で起きることがよくあります。データベースの接続プールが枯れたり、設定が1つ狂ったPodが1台だけ、特定のリクエストに500を返したりします。readinessプローブは相変わらず200なので、KubernetesはそのPodをエンドポイントに置き続けます。Podが3つなら、リクエストの3分の1が失敗し、誰かがログを見るまでそのままです。
クライアント側のプロキシはレスポンスを直接受け取るので、これを知っています。同じアップストリームが続けて失敗したら、そのアップストリームだけをしばらく外せば足ります。Envoyの外れ値検出(outlier detection)がその役目で、IstioはDestinationRuleのoutlierDetectionで有効にします。
どう動くのか
外れ値検出: アップストリームのホストを1つずつ別々に見ます。
| DestinationRule | Envoyクラスター | 意味 |
|---|---|---|
consecutive5xxErrors: 2 |
consecutive5xx: 2 |
連続する5xxがこの回数になったら排除 |
interval: 2s |
interval: "2s" |
排除するかどうかを判定する周期 |
baseEjectionTime: 60s |
baseEjectionTime: "60s" |
1回排除されるときの基本の時間 |
maxEjectionPercent: 50 |
maxEjectionPercent: 50 |
1度に外せるホストの最大割合 |
排除はそのサイドカーのロードバランシングテーブルでだけ起きます。Kubernetesのエンドポイントはそのままで、他のクライアントのサイドカーは、自分が受け取ったレスポンスで別々に判断します。排除されたホストは、基本の排除時間が過ぎると戻り、また失敗すれば排除された回数に比例して、より長く外れます。maxEjectionPercentは、障害がすべてのホストに広がったときに、全部を外してしまってどこにも行けなくなることを防ぐ安全装置です。
見えるようにする。Istioは、サイドカーが出すEnvoyの統計をデフォルトでフィルタします。排除の回数(outlier_detection.ejections_enforced_total)を見るには、Podのアノテーションproxy.istio.io/configのproxyStatsMatcherでその統計を復活させる必要があり、プロキシが起動するときに読み込むので、Podを作り直す必要があります。排除されたホストは、istioctl proxy-config endpointsでOUTLIER CHECKがFAILEDと表示されます。
ミラーリング: VirtualServiceのmirrorは、リクエストを複製して別のサービスへ送り、そのレスポンスを捨てます。複製は元のリクエストと同じx-request-idを付けて行くので、受け取る側のログで対を探せます。新しいバージョンを本番のトラフィックで試しつつ、ユーザーには元のバージョンのレスポンスだけを返します。
障害注入: VirtualServiceのfaultは、クライアント側のサイドカーがリクエストを送る前に、遅延(delay)や中止(abort)を入れます。中止されたリクエストはアップストリームに届かず、アクセスログのレスポンスフラグがFIになります。ヘッダー条件を付ければ、試すリクエストだけを壊せます。
現場での姿
Podが3つのうち1つがずっと500を返しているのに、誰も気づかなかった場合です。readinessプローブが通る故障です。外れ値検出をかけておくと、ユーザーが見るエラーが数回で止まります。その代わり故障そのものが隠されるので、排除の統計にアラートをかける必要があります。
外れ値検出を有効にしたらホストが全部外れた場合です。アップストリーム全体が遅くなったときに、maxEjectionPercentを100にしていると起きます。全部外すと行き先がなく、かえって障害が大きくなります。
ミラーリングを有効にしたら、新しいバージョン側のデータベースに注文が2回入った場合です。ミラーはレスポンスを捨てるだけで、リクエストは本当に処理されます。副作用のあるリクエスト(書き込み)は、ミラーの対象から別に外す必要があります。
公式ドキュメント: DestinationRule — OutlierDetection・Mirroring・Fault Injection・Envoy outlier detection・ProxyConfig proxyStatsMatcher
次のラボですること
常に500を返すPodを1つ、正常なPod2つと同じサービスの後ろに置き、失敗率を先に測ります。統計を復活させた後、外れ値検出をかけて、エラーが止まることと、EnvoyがそのPodを排除している様子を確認し、ミラーリングとヘッダー条件の障害注入を加えます。最後に、これらの設定がEnvoyの設定のどの欄になったかを取り出して見ます。