web-dev-qa-db-ja.com

gRPCクライアント側の負荷分散

Pythonとしてkubernetesポッド内のクライアント/サーバーとしてgRPCを使用しています...同じタイプの複数のポッド(gRPCサーバー)を起動してクライアントに接続させたいと思いますそれら(ランダムに)。

サーバーのポッドを10個ディスパッチし、それらを対象とする「サービス」をセットアップしました。次に、クライアントで、サービスのDNS名に接続しました。つまり、kubernetesが負荷分散を実行して、ランダムなサーバーポッドに誘導する必要があります。実際には、クライアントはgRPC関数を呼び出します(これは適切に機能します)が、ログを見ると、すべての呼び出しが同じサーバーポッドに送信されていることがわかります。

クライアントが何らかのDNSキャッシングを行っているため、すべてのコールが同じサーバーに送信されると思います。これは事実ですか?とにかくそれを無効にし、同じスタブクライアントを設定して「新しい」呼び出しを行い、呼び出しごとにDNSで新しいIPをフェッチしますか?

DNSサーバーに毎回クエリを実行する場合に発生する可能性があるオーバーヘッドを認識していますが、現時点では、負荷を分散することの方がはるかに重要です。

19
Idan

物事がどのように機能することになっているのかを説明することによって、答える機会を得ましょう。

クライアント側のLBがgRPC Cコア(JavaおよびGoフレーバーまたはgRPCを除くすべての基盤)で機能する方法)は次のとおりです(信頼できるドキュメントは here ):

クライアント側のLBはシンプルに保たれ、意図的に「ばかげています」。複雑なLBポリシーを実装するために選択した方法は、外部LBサーバーを経由する方法です(前述のドキュメントで説明されています)。このシナリオは関係ありません。代わりに、(デフォルト)pick-firstLBポリシーを使用するチャネルを作成するだけです。

LBポリシーへの入力は、解決されたアドレスのリストです。 DNSを使用している場合、foo.comが[10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4]に解決されると、ポリシーはそれらすべてへの接続を確立しようとします。正常に接続する最初のものは、切断されるまで選択されたものになります。したがって、「ピックファースト」という名前です。より長い名前は「最初に選択して、できるだけ長くそれを使い続ける」ことができたかもしれませんが、それは非常に長いファイル名になりました:)。選択されたアドレスが切断されると、選択されたポリシーは次の正常に接続されたアドレス(内部では「接続されたサブチャネル」と呼ばれます)があればそれを返すように移行します。繰り返しますが、接続されたままである限り、この接続されたサブチャネルを選択し続けます。それらすべてが失敗した場合、呼び出しは失敗します。

ここでの問題は、本質的にプルベースであるDNS解決が、1)チャネルの作成時、および2)選択した接続されたサブチャネルの切断時にのみトリガーされることです。

現在のところ、ハッキーな解決策は、すべてのリクエストに対して新しいチャネルを作成することです(非常に非効率的ですが、設定によってはうまくいくでしょう)。

2017年第1四半期に予定されている変更( https://github.com/grpc/grpc/issues/7818 を参照)により、クライアントは別のLBポリシー、つまりラウンドロビンを選択できるようになります。さらに、クライアント構成に「ランダム化」ビットを導入することを検討する場合があります。これにより、アドレスに対してラウンドロビンを実行する前にアドレスをシャッフルして、意図したとおりに効果的に達成します。

16

通常のK8S負荷分散はgRPCでは機能しません。次のリンクはその理由を説明しています。 https://kubernetes.io/blog/2018/11/07/grpc-load-balancing-on-kubernetes-without-tears/

これは、gRPCがHTTP/2に基づいて構築されており、HTTP/2が長寿命の単一のTCP接続を持つように設計されているため、すべての要求が多重化されます。つまり、複数の要求をアクティブにすることができます。いつでも同じ接続を使用できます。これは、接続管理のオーバーヘッドを削減するため、通常は優れています。しかし、これは(ご想像のとおり)接続レベルのバランスがあまり役に立たないことも意味します。すべてのリクエストは1つの宛先ポッドに固定されます。

最近のほとんどのイングレスコントローラーはこれを処理できますが、オーブンの温度が高い(nginx)か、アルファバージョン(traefik)であるか、最新バージョンのK8S(Linkerd)が必要です。 Javaソリューション ここ )を見つけることができるクライアント側の負荷分散を行うことができます。

1
Abhijit Sarkar

Vanilla Kubernetesサービスを作成した場合、サービスには独自の負荷分散仮想IPが必要です(サービスのkubectl get svc your-serviceCLUSTER-IPが表示されているかどうかを確認してください)。この場合、その単一の仮想IPが実際のバックエンド間でトラフィックを分割しているため、DNSキャッシングは問題になりません。

kubectl get endpoints your-serviceを試して、サービスが実際にすべてのバックエンドを認識していることを確認してください。

headless service がある場合、DNSルックアップは10個のIP(ポッドごとに1つ)のAレコードを返します。クライアントが常にAレコードの最初のIPを選択している場合、それはまた、表示されている動作を説明します。

0
CJ Cullen