多くの連鎖的な障害シナリオでよくある問題は、サーバーがクライアントの期限をすでに超えているリクエストを処理するために大量のリソースを消費していることです。その結果、サーバーは価値のある処理を何も行わずに大量のリソースを消費してしまいます。タイムアウトしたリクエストに返信しても意味がありません。
タイムアウト制御は、サービスの安定性を確保するための重要な防御線であると言えます。その本質はフェイルファストであることです。優れたタイムアウト制御戦略により、高レイテンシーのリクエストをできるだけ早くクリアし、リソースをすぐに解放できます。リクエストの蓄積を可能な限り回避します。
リクエストに複数のステージがある場合 (一連の RPC 呼び出しで構成される場合など)、サービスは各ステージの開始前にチェックする必要があります。期限は無駄な作業を避けるため、つまりリクエストを処理するのに十分な時間が残っているかどうかを確認するためのものです。
一般的な実装エラーは、各 RPC サービスに固定タイムアウトを設定することです。各サービス間でタイムアウトを渡す必要があります。タイムアウトは、最初のリクエストによってサービス呼び出しのトップレベルで設定できます。トリガーされた RPC ツリーには、同じ絶対期限が設定されます。たとえば、サービス リクエストの最上位でタイムアウトを 3 秒に設定します。サービス A がサービス B をリクエストします。サービス B の実行には 1 秒かかります。その後、サービス B がサービス C をリクエストします。このとき、タイムアウト時間は 2 秒のままです。サービス C には時間がかかります。実行まで 1 秒。これは、サービス C がサービス D を要求したとき、サービス D の実行には 500 ミリ秒かかるなどです。理想的には、同じタイムアウト配信メカニズムが呼び出しチェーン全体で使用されます。
タイムアウト配信メカニズムが使用されていない場合、次の状況が発生します。
サービス B がタイムアウト配信メカニズムを採用している場合、期限に達しており、サービス C でリクエストは直ちに破棄される必要があります。クライアントがエラーを報告した可能性があります。タイムアウト配信を設定する場合、ネットワークの送信時間やクライアントが応答を受信した後の処理時間を考慮して、通常は配信期限を 100 ミリ秒などに短縮します。
Mysql、Redis、MySQL など、サービス間のタイムアウト送信だけでなく、プロセス内でのタイムアウト送信も必要です。プロセス内でシリアルに呼び出されます。サービス B の場合、合計リクエスト時間を 3 秒に設定します。Mysql をリクエストしてから、再度 Redis をリクエストするのに 1 秒かかります。タイムアウトは 2 秒です。Redis を実行してからサービス B をリクエストするのに 500 ミリ秒かかります。タイムアウトは各ミドルウェアまたはサービスが構成ファイルで固定タイムアウトを設定するため、残り時間と設定時間の最小値を取得する必要があります。
コンテキストの原理は非常に単純ですが、関数は非常に強力であり、 go も実装されました コンテキストのサポートに加えて、さまざまなオープンソース フレームワークでもコンテキストのサポートが実装され、コンテキストが標準となり、タイムアウト配信もコンテキストに依存します。
通常、タイムアウトを 3 秒に設定するなど、タイムアウト制御転送のためにサービスの最上位層に初期コンテキストを設定します。
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)defer cancel()
コンテキスト転送が実行されるとき (たとえば、上図の場合、以下の方法で残り時間を取得し、Redis が設定しているタイムアウトと比較して小さい方の時間を取得します
dl, ok := ctx.Deadline()
timeout := time.Now().Add(time.Second * 3)if ok := dl.Before(timeout); ok { timeout = dl}
サービス間のタイムアウト転送とは、主に RPC 呼び出し時のタイムアウト転送を指します。追加の処理については、gRPC 自体がタイムアウト配信をサポートしています。原理は上記と同様です。メタデータを通じて配信され、最終的には次のように grpc-timeout の値に変換されます。コード grpc-go/internal/transport/handler_server. go:79
if v := r.Header.Get("grpc-timeout"); v != "" { to, err := decodeTimeout(v) if err != nil { return nil, status.Errorf(codes.Internal, "malformed time-out: %v", err) } st.timeoutSet = true st.timeout = to}
タイムアウト配信はサービスの安定性を確保するための重要な防御線です。原理と実装は非常にシンプルです。タイムアウトあり配信はフレームワークに実装されていますか?そうでない場合は、すぐに行動を起こしてください。
go-zero でのタイムアウト配信は、構成ファイル API ゲートウェイ
の Timeout
および # # を通じて構成できます。 #rpc サービスのタイムアウト。サービス間で自動的に渡されます。
記事では、Go タイムアウト コントロールの実装方法を理解しています。 タイムアウト コントロールの使用方法について説明しています。
go-zero と
star/fork を使用して私たちをサポートしてください。
以上がマイクロサービスのタイムアウト配信を理解するための 1 つの記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。