Advent Calendar 2020 全部オレシリーズ 14日目です。誕生日記念号です。おめでとうございます。ありがとうございます。
gRPC と connection leak の話
先日も gRPC と NLB での idle timeout の問題について触れましたが、今回は Istio の Ingress Gateway で NLB の idle timeout に対応する方法です。
Go言語ではクライアント側もサーバー側もデフォルトで15秒間隔の TCP keepalive が有効になるということも書きましたが、Istio を導入した環境では、サーバーの接続相手は localhost の Envoy (istio-proxy) となるため、TCP keepalive もその間で閉じてしまってクライアントには届きません。クライアントと TCP 接続するのは Istio Ingress Gateway なのです。
また、クライアント視点ではクライアントから keepalive を送っておけば問題なさそうに見えますが、サーバー側からも送っておかないと、黙っていなくなられるともう相手がいないコネクションをずっと維持することになってしまい、ファイルディスクリプタが溢れたり、無駄なメモリを使ってしまいます。
クライアントと直接接続している Istio Ingress Gateway が TCP keepalive を送ってくれれば良いわけですが、Istio のドキュメントをみても TCP keepalive の設定項目があるのは DestinationRule だけです。
それで、ググっていたら見つかりました。
https://github.com/envoyproxy/envoy/issues/3634
Enovy の issue #3634 で「downstream の TCP keepalive を設定したいんだけど」というのがあり、それは socket_options でできるよということでした。さらに Gardener という Kubernetes-as-a-service を構築するプロジェクトでそれを EnvoyProxy で実装したという PullRequest へのリンクもありました。ありがたや、ありがたや。
https://github.com/gardener/gardener/pull/3104
Envoy Filter で TCP keepalive の設定を行う
ということで次のような EnvoyFilter を適用すれば Istio Ingress Gateway で downstream (クライアント向け) の TCP keepalive を設定することができます。
match のところを見るとわかりますが、この書き方の場合、listener の port ごとに configPatches に並べる必要があります。
| |
この設定を使うと、最後の通信から15秒後から15秒間隔で keepalive を送信します。3回連続で応答がなかったら RST を送って強制切断します。TCP_KEEPINTVL の間レスポンスを待つという感じで TCP_KEEPIDLE の15秒待った後、15秒を3回で60秒後に RST が送られます。3回目を送った直後ではありません。


