ListWatchからWatchListへ

ListWatchからWatchListへ

分析する

まず、自分で実装する場合にどのように設計するかを想像することができます。 Informer は現在 ListWatch メカニズムであり、サーバーはストリーミング List をサポートしていないため、クライアントとサーバーの両方が適応する必要があるのは避けられません。したがって、予備的な方向性は次のようになります。

  1. サーバーはストリーミングリストリクエストをサポート
  2. Informerはサーバー側APIの変更に適応します

クライアントの適応は比較的単純であり、サーバー側でそれをどのように実装するかに依然として焦点が当てられています。まず、前回の Stale Read で紹介した以前のリストのロジックを確認しましょう。

便宜上、以下のテキストでは Resourceversion を表すために RV を使用します。このセクションのロジックはバージョン v1.26.9 に基づいており、ページングは​​ Etcd を通じて直接実行されるため、ページング クエリは無視されます。

List リクエストでも Watch リクエストでも、そのクエリは RV での受け渡しをサポートします。サーバーは、要求されたさまざまな RV に応じて対応する処理を行います。 RV の値に応じて、次の 3 つのケースに分けられます。

  1. 設定されていないか、RV="" が明示的に設定されている
  2. RV = "0"
  3. RV = 「ゼロ以外の値」

最初の 2 つのケースでは、List は WatchCache Store のコンテンツ、つまりサーバーによってキャッシュされた Etcd の関連データすべてを直接返します。

3 番目のケースでは、サーバーはキャッシュされたデータの最大バージョンが渡された RV を超えるまで待機してから、キャッシュ内のデータを返します。一定時間 (3 秒) 待ってもキャッシュ内のデータが指定されたバージョンに到達しない場合は、「リソース バージョンが大きすぎます」というエラー メッセージが返され、クライアントは 1 秒後に再試行するように指示されます。

新しいバージョンでは、リストの古い読み取りの問題が修正されました。最初の 2 つのケースでは、まず kube-apiserver から Etcd の最新の RV を取得し、WatchCache Store のコンテンツが RV に追いつくのを待ってから、すべてを一度に返します。

つまり、サーバーは最新の完全なデータがすでにあるかどうかを認識し、それに基づいてストリーミング形式でデータを返すことができます。既存のストリーミング API は Watch なので、これに基づいて List 効果をサポートできます。リストのリクエストに基づいて変更してみませんか?リストを変更すると、クライアント側の調整が過度に必要になるためです。 List は単独で使用されることが多いですが、Watch は基本的に Informer で使用されます。

したがって、最終的な作業は、Watch API を使用して List 効果を実現する方法になりますが、データは引き続きストリーミング形式でクライアントに返され、同時に、Informer は ListWatch メソッドを変更して、Watch API のみを使用して以前の効果を実現します。以下の記事では主にサーバーの実装を詳しく紹介し、クライアントの適応部分については簡単に紹介します。

原理

Watch API に SendInitialEvents=true パラメータを追加することで、リスト効果をサポートします。 Watch リクエストを受信した後、サーバーは InitEvents としてクライアントに送信するデータを決定します。これらのデータを送信した後、サーバーは、InitEvents が送信されたことをクライアントに通知するサインとして、特定の BOOKMARK イベント (RV が以下の bookmarkAfterRV に対応する特定の注釈を持つ BOOKMARK) をクライアントに送信します。指定された BOOKMARK イベントを受信した後、クライアントは以前に受信したすべての InitEvents を List の結果として処理します。

タイミング図

以下はv1.29コードに基づいた分析です。現時点では、v1.29 はまだアルファ状態です。記載されている古いバージョンは 1.27 より前のバージョンを指し、新しいバージョンは v1.29 を指します。表示されるコードが以下の説明と一致しない場合は、コードのバージョンが原因である可能性があります。

写真

WatchCache から始まり、右側の青い 4 つは kube-apiserver の起動時に実行されます。 G1 と G2 は、Etcd からデータを取得し、クライアントの CacheWatcher 入力チャネルにデータを送信するために使用される 2 つの goroutine を表します。

  1. G1.1 各リソース タイプは、リフレクターを含むキャッチャーに対応します。 WatchCache は、Etcd から取得したデータを保存する Reflector のストアとして機能します。
  2. G1.2 Reflector はデータを取得するために Etcd List および Watch API の呼び出しを開始します。
  3. G1.3 Reflector は取得したデータを使用して、WatchCache のストアと循環バッファを更新します。これらのストアと循環バッファは、それぞれオブジェクトの全量とオブジェクトの最新の更新イベントを保存するために使用されます。
  4. G1.4 WatchCache を更新した後、Cacher の着信チャネルにイベントを送信します。
  5. G2.1 は、Cacher の受信チャネルからデータを消費し、それをすべての CacheWatcher の入力チャネルに送信するか、RV > bookmarkAfterRV の BOOKMARK イベントをすべての CacheWatcher の入力チャネルに定期的 (1 ~ 1.25 秒) に送信します。

上記のプロセスは、サーバー起動時のデータ処理フローを説明しています。次に、クライアントからのリクエストがあった場合の処理​​フローを見てみましょう。

  1. Reflector は初めて Watch リクエストを開始し、クエリで RV=""&sendInitialEvent=true&resourceVersinotallow=NotOlderThan&AllowWatchBookmarks=true を指定します。ここで、RV="" と RV="0" の両方で List 効果を実現できますが、旧バージョンと比較すると、新バージョンの Watch リクエストでは RV="" に対して特別な処理が行われ、Watch API Stale Read の問題が解決されています (List Stale Read については前回の記事で紹介しました。List には Consistent Read を有効にするかどうかを制御するための FeatureGate が用意されていますが、Watch には対応する FeatureGate がないため、新バージョンの RV="" のリクエストは Consistent Read である必要があります)。リクエストを受信すると、サーバーはこのリクエストに対応する CacheWachter オブジェクトを作成します。
  2. リクエストを受信すると、サーバーは bookmarkAfterRV の値を計算します。 RV="0" の場合、bookmarkAfterRV は WatchCache RV (WatchCache ストア データ内の最大 RV) になります。 RV="" の場合、Etcd から最大 RV を bookmarkAfterRV として取得し、bookmarkAfterRV を CacheWatcher に渡します。最後に、CacheWatcher は WatchCache Store のデータと独自の入力チャネルを組み合わせて InitEvents を準備します。

2a WatchCache ストアから返されるデータの取得を開始します。このときの処理ロジックは旧バージョンと同じです。ストア内のすべてのデータが返され、次のステップのためにストア データの最大 RV が記録されます。

2b 入力チャネル内のイベントを消費し、その RV が 2a で渡された RV より大きいかどうかを比較します。それが BOOKMARK タイプであり、その RV が 2a で渡された RV と等しく、bookmarkAfterRV イベントが送信されていない場合、この BOOKMARK イベントはリストの終了と見なされ、Annotation: k8s.io/initial-events-end が設定され、最終的にクライアントに送信されます。

これまで、サーバーの主なプロセスが紹介され、クライアント Informer も対応する適応を行いました。 WatchList 機能がオンになっている場合は、完全なデータを取得するために Watch 要求が送信されます。アノテーション k8s.io/initial-events-end を含む BOOKMARK イベントを受信すると、その RV が記録され、この期間中に受信および処理されたオブジェクトがリスト結果として使用されます。最後に、上記の RV をパラメータとして Watch リクエストが再度呼び出されます。このステップからは、Informer の従来の Watch ロジックになります。

データフロー

写真

この画像は KEP 3157 ウォッチリストから取得したもので、実際にはタイミング図も含まれています。しかし、本のシーケンス図のタイミング図には、コードと一致しない問題がいくつかあります。したがって、タイミング図はここでは直接使用されず、再描画されます。

上記の 2 つの図を組み合わせると、全体のプロセスを理解できます。上図の a はタイミング図の 2a に対応し、b はタイミング図の 2b に対応し、c はタイミング図の G2.1 に対応します。下部の白い部分はタイミング図のG1のロジック、つまりEtcdからデータを取得することに対応しています。クライアント要求の処理は上から下へ行われ、データの返送は下から上へ行われます。

知らせ

上記の処理ロジックには多くの詳細があり、特別な注意が必要です。

  1. Watch API (RV="" WatchList 関数) の古い読み取り問題を修正しました。これは基本的にリストの古い読み取りを排除するためのものですが、Watch API に実装されています。前の記事と組み合わせると、List API を直接使用するか WatchList を使用するかに関係なく、Stale Read の問題を回避できます。
  2. WatchCache Store のデータと Cacher の imcomming chan データは絡み合っているため、2a がすべての Store データを処理した後、最大の RV が記録され、imcomming chan データの処理時に使用するために 2b に渡されます。時間の逆流を避けるために、イベント RV > RV の非 BOOKMARK イベントのみがクライアントに送り返されます。
  3. CacheWatcher の入力チャネルに RV < bookmarkAfterRV のイベントはありません。 G2.1 が Cacher から着信チャネルを消費し、それをすべての CacheWatcher 入力に送信すると、イベント タイプが BOOKMARK であり、RV < bookmarkAfterRV である場合、入力チャネル バッファ サイズが制限されているため、イベントは直接破棄されます。 Cacher は作成された後、入力にデータの書き込みを開始し、2a がストア内のすべてのデータを処理した後、入力チャネルの消費を開始します。その間には時差があります。イベントの長さはストア内のデータの量に関係します。不要な BOOKMARK イベントを破棄すると、入力チャネルの負荷を軽減できます。これには、入力チャネルへのイベント処理ロジックの追加が含まれます。これには、単一の CacheWatcher によってプロセス全体がブロックされるのを回避するためにバッファーがいっぱいになったときの処理方法や、データ例外の処理方法など、さまざまな特殊な状況の処理が含まれます。
  4. 最終的にクライアントに送り返される特定の注釈を運ぶ BOOKMARK イベントの RV は >= bookmarkAfterRV です。 bookmarkAfterRV と同じではないことに注意することが非常に重要です。元の KEP タイミング図のここ (2c) の説明は間違っています。根本的な原因は、ブックマーク タイマーの周期が 1 ~ 1.25 秒であること、つまり BOOKMARK イベントが 1 ~ 1.25 秒ごとに生成され、その RV が着信チャネルの最大 RV であることです。まさにこの時間間隔と 3 の説明を組み合わせることで、G2.1 によって送信される最初の有効な BOOKMARK イベント (CacheWatcher 入力チャネルに入る) の RV は >= bookmarkAfterRV になります。これはまた、bookmarkAfterRV BOOKMARK イベントを返す前に返された有効な負荷を運ぶすべてのイベント セットの最大 RV も >= bookmarkAfterRV であることも間接的に示しています。つまり、マークは bookmarkAfterRV ですが、リストの結果には bookmarkAfterRV よりも大きいデータが含まれています。個人的には、これはまだ最適化できると思います。リストの時間消費は、ブックマーク タイマー サイクル (1 ~ 1.25 秒) によって短縮できます。 2b で非 BOOKMARK イベントを処理する場合は、RV == bookmarkAfterRV であり、bookmarkAfterRV BOOKMARK イベントが送信されていないと判断するだけで済みます。このとき、bookmarkAfterRV BOOKMARK をクライアントに直接返すことができます。大量のデータの場合、すべてのデータを返すのにかかる時間が Watch のタイムアウト時間 (約 1 秒) を超えると、タイムアウトの可能性が減り、WatchList プロセスの繰り返し実行が回避され、メモリ消費をある程度削減できます。

要約する

この記事では、WatchList の実装原理とロジックを主に分析し、いくつかの詳細を説明します。詳細については後ほどコミュニティとさらに話し合う予定です。この KEP では、kube-apiserver のメモリ負荷を軽減するための 2 つの変更も導入されています。スペースの都合上、次回の記事で紹介させていただきます。同時に、すべての最適化作業が完了する前と完了した後の効果の比較も示します。乞うご期待〜

<<:  ガートナー: クラウドネイティブテクノロジーを導入してデジタル変革を加速する方法

>>:  5 種類のクラウド環境に対する包括的な防御ガイド

推薦する

Green Radish アルゴリズムの応答戦略と処理方法の分析

2013年の初めに、百度は再びアルゴリズムをアップグレードし、2月19日に青大根アルゴリズムをリリー...

エッジからクラウドへの進化における4つの大きな課題

エッジツークラウド設定の使用は大幅に増加していますが、レイテンシー、データセキュリティ、スケーラビリ...

適切な SEO 会社を見つけるための 7 つのステップ

1. 月次レポートこれは必要なステップです。ウェブサイトの所有者は、毎月何が行われ、どのような進捗状...

彼らは大量のサーバーをあなたに押し付け、クラウドコストを50%削減したいと考えている

ここ二日間、杭州は曇りと雨が続いています。灰色の雲奇会議会場で最も目を引くのは、赤く塗られたこの大き...

Volcano Engineが自社開発のビデオコーデックチップをリリース

Volcano Engine Video Cloudは8月22日、自社開発のビデオコーデックチップの...

SEOに関する4つの基礎コースから学んだこと

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています私はもう若...

クラウドセキュリティに影響を与える3つの要素

企業はクラウド プラットフォームに移行しており、CIO はセキュリティに関する考え方を変える必要に迫...

ウェブサイトの長所と短所を分析する方法

最近、友人から、ウェブサイトの長所と短所を分析し、それをウェブサイトの最適化と宣伝にまで拡張するには...

NetEase Cloud Computingのブランド戦略のアップグレード:あらゆる組織に独自のデジタル競争力を構築

知性の波が押し寄せています。デジタル化とインテリジェンスは人々の仕事や生活を変えるだけでなく、業界に...

インターネット起業における両者の相互作用について

最近、Tianya の投稿をフォローしています。約 2,000 ページの長さですが、まだ終わっていま...

総合分析:クラウドコンピューティング技術の現状、特徴、問題点

[[236341]]クラウドコンピューティングの現状はどうなっていますか?新しいテクノロジーについて...

2019 年のトップ 10 DevOps ツール、いくつ使用していますか?

この記事では、必要なツールを選択するための詳細な参考情報を提供するために、ツールのリストをまとめてい...

誰もがSEO担当者と呼べるわけではない

みなさんこんにちは。私は魏東東です。久しぶりに真面目に記事を書きました。今日は気分が落ち込んでいるの...

無料URL短縮サービスBitlyが1500万ドルを調達

URL短縮サービスプロバイダーのBitlyは今年5月に2000万ドルの資金調達を計画していたが、まだ...