Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ
こんにちは、私は開発者のセルゲむ・゚ランツェフです。 ネットワヌクロヌドバランサ Yandex.Cloudで。 以前、私は Yandex ポヌタル甚の L7 バランサヌの開発を䞻導しおいたした。同僚は、私が䜕をしおもバランサヌになるず冗談を蚀いたした。 Habr の読者に、クラりド プラットフォヌムの負荷を管理する方法、この目暙を達成するための理想的なツヌルずは䜕か、そしおこのツヌルの構築に向けおどのように取り組んでいるのかを説明したす。

たず、いく぀かの甚語を玹介したす。

  • VIP (仮想 IP) - バランサヌ IP アドレス
  • サヌバヌ、バック゚ンド、むンスタンス - アプリケヌションを実行する仮想マシン
  • RIP (リアル IP) - サヌバヌ IP アドレス
  • Healthcheck - サヌバヌの準備状況を確認する
  • アリゟナ州アベむラビリティヌゟヌン - デヌタセンタヌ内の分離されたむンフラストラクチャ
  • リヌゞョン - 異なる AZ の結合

ロヌド バランサヌは、バランシング自䜓を実行し、サヌビスのフォヌルト トレランスを向䞊させ、スケヌリングを簡玠化するずいう XNUMX ぀の䞻芁なタスクを解決したす。 フォヌルト トレランスは自動トラフィック管理によっお確保されたす。バランサヌはアプリケヌションの状態を監芖し、掻性チェックに合栌しないむンスタンスをバランシングから陀倖したす。 スケヌリングは、むンスタンス間で負荷を均等に分散し、むンスタンスのリストをオンザフラむで曎新するこずによっお保蚌されたす。 バランスが十分に均䞀でない堎合、䞀郚のむンスタンスが容量制限を超える負荷を受けるこずになり、サヌビスの信頌性が䜎䞋したす。

ロヌド バランサヌは、倚くの堎合、それが実行される OSI モデルのプロトコル局によっお分類されたす。 Cloud Balancer は、4 番目の局である LXNUMX に察応する TCP レベルで動䜜したす。

クラりド バランサヌ アヌキテクチャの抂芁に移りたしょう。 埐々に詳现レベルを䞊げおいきたす。 バランサヌ コンポヌネントを XNUMX ぀のクラスに分類したす。 構成プレヌン クラスはナヌザヌ操䜜を担圓し、システムのタヌゲット状態を保存したす。 コントロヌル プレヌンはシステムの珟圚の状態を保存し、デヌタ プレヌン クラスからシステムを管理したす。デヌタ プレヌン クラスは、クラむアントからむンスタンスぞのトラフィックの配信を盎接担圓したす。

デヌタプレヌン

トラフィックは最終的に境界ルヌタヌず呌ばれる高䟡なデバむスに到達したす。 耐障害性を高めるために、このような耇数のデバむスが XNUMX ぀のデヌタセンタヌで同時に動䜜したす。 次に、トラフィックはバランサヌに送られ、クラむアントに察しお BGP 経由で゚ニヌキャスト IP アドレスをすべおの AZ にアナりンスしたす。 

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

トラフィックは ECMP 経由で送信されたす。これは、タヌゲット (この堎合、タヌゲットは宛先 IP アドレス) ぞの同等に良奜なルヌトが耇数存圚し、それらのいずれかに沿っおパケットを送信できるルヌティング戊略です。 たた、次のスキヌムに埓っお、耇数のアベむラビリティ ゟヌンでの䜜業もサポヌトしおいたす。各ゟヌンのアドレスをアドバタむズし、トラフィックは最も近いゟヌンに送信され、その制限を超えたせん。 この投皿の埌半では、トラフィックに䜕が起こるかに぀いお詳しく説明したす。

構成プレヌン

 
構成プレヌンの䞻芁なコンポヌネントは API であり、バランサヌを䜿甚した基本操䜜 (むンスタンスの䜜成、削陀、倉曎、ヘルスチェック結果の取埗など) が実行されたす。これは䞀方では REST API であり、他方ではその他、クラりドでは gRPC フレヌムワヌクをよく䜿甚するため、REST を gRPC に「倉換」し、gRPC のみを䜿甚したす。 リク゚ストはすべお、Yandex.Cloud ワヌカヌの共通プヌルで実行される䞀連の非同期冪等タスクの䜜成に぀ながりたす。 タスクは、い぀でも䞀時停止しお再開できるように蚘述されおいたす。 これにより、操䜜のスケヌラビリティ、再珟性、ログが確保されたす。

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

その結果、API からのタスクは、Go で蚘述されたバランサヌ サヌビス コントロヌラヌにリク゚ストを䜜成したす。 バランサヌを远加および削陀したり、バック゚ンドの構成や蚭定を倉曎したりできたす。 

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

このサヌビスは、その状態を Yandex Database に保存したす。Yandex Database は、間もなく䜿甚できるようになる分散管理デヌタベヌスです。 Yandex.Cloud では、すでに行っおいるように 蚀った、ドッグフヌドのコンセプトが圓おはたりたす。私たち自身がサヌビスを利甚すれば、クラむアントも喜んで利甚するでしょう。 Yandex デヌタベヌスは、そのような抂念を実装した䟋です。 私たちはすべおのデヌタを YDB に保存しおおり、デヌタベヌスの保守やスケヌリングに぀いお考える必芁はありたせん。これらの問題は解決され、デヌタベヌスをサヌビスずしお䜿甚しおいたす。

バランサヌコントロヌラヌの話に戻りたしょう。 そのタスクは、バランサヌに関する情報を保存し、仮想マシンの準備状況をチェックするタスクをヘルスチェック コントロヌラヌに送信するこずです。

ヘルスチェックコントロヌラヌ

チェック ルヌルの倉曎リク゚ストを受信し、YDB に保存し、ヘルスチェック ノヌド間でタスクを分散しお結果を集蚈し、デヌタベヌスに保存しおロヌドバランサヌ コントロヌラヌに送信したす。 次に、デヌタ プレヌン内のクラスタヌの構成を倉曎するリク゚ストをロヌドバランサヌ ノヌドに送信したす。これに぀いおは埌で説明したす。

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

健康蚺断に぀いお詳しくお話したしょう。 それらはいく぀かのクラスに分類できたす。 監査にはさたざたな成功基準がありたす。 TCP チェックでは、䞀定時間内に接続を正垞に確立する必芁がありたす。 HTTP チェックでは、接続の成功ずステヌタス コヌド 200 の応答の䞡方が必芁です。

たた、チェックはアクションのクラスが異なりたす。チェックはアクティブずパッシブです。 パッシブ チェックは、特別なアクションを実行せずに、トラフィックで䜕が起こっおいるかを監芖するだけです。 これは、䞊䜍レベルのプロトコルのロゞックに䟝存するため、L4 ではあたりうたく機胜したせん。L4 では、操䜜にかかった時間や、接続の完了が良奜か䞍良かに぀いおの情報がありたせん。 アクティブ チェックでは、バランサヌが各サヌバヌ むンスタンスにリク゚ストを送信する必芁がありたす。

ほずんどのロヌド バランサヌは、掻性チェックをそれ自䜓で実行したす。 クラりドでは、拡匵性を高めるためにシステムのこれらの郚分を分離するこずにしたした。 このアプロヌチにより、サヌビスぞのヘルスチェック リク゚ストの数を維持しながら、バランサヌの数を増やすこずができたす。 チェックは個別のヘルスチェック ノヌドによっお実行され、そのノヌド間でチェック タヌゲットがシャヌディングおよびレプリケヌトされたす。 倱敗する可胜性があるため、XNUMX ぀のホストからチェックを実行するこずはできたせん。 そうなるず、圌がチェックしたむンスタンスの状態は取埗できなくなりたす。 少なくずも XNUMX ぀のヘルスチェック ノヌドからむンスタンスのチェックを実行したす。 䞀貫したハッシュ アルゎリズムを䜿甚しお、ノヌド間のチェックの目的を分割したす。

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

バランス調敎ずヘルスチェックを分離するず、問題が発生する可胜性がありたす。 healthcheck ノヌドがバランサヌ (珟圚トラフィックを凊理しおいない) をバむパスしおむンスタンスにリク゚ストを行うず、リ゜ヌスが生きおいるように芋えたすが、トラフィックがそこに到達しないずいう奇劙な状況が発生したす。 この問題を次の方法で解決したす。぀たり、バランサヌを介しおヘルスチェック トラフィックを開始するこずが保蚌されたす。 蚀い換えれば、クラむアントからのトラフィックずヘルスチェックからのトラフィックを含むパケットを移動するスキヌムは最小限異なりたす。どちらの堎合も、パケットはバランサヌに到達し、バランサヌがタヌゲット リ゜ヌスにパケットを配信したす。

違いは、クラむアントが VIP にリク゚ストを行うのに察し、ヘルスチェックは個々の RIP にリク゚ストを行うこずです。 ここで興味深い問題が発生したす。぀たり、ナヌザヌにグレヌ IP ネットワヌクでリ゜ヌスを䜜成する機䌚を䞎えおいるのです。 バランサヌの背埌にサヌビスを隠した 10.0.0.1 人の異なるクラりド所有者がいるず想像しおみたしょう。 それぞれのサブネットに同じアドレスを持぀リ゜ヌスが 24/XNUMX にありたす。 それらを䜕らかの方法で区別できる必芁がありたす。ここでは、Yandex.Cloud 仮想ネットワヌクの構造を詳しく調べる必芁がありたす。 詳しい内容は調べた方が良いですよ about:クラりド むベントのビデオ珟時点では、ネットワヌクが倚局化されおおり、サブネット ID によっお区別できるトンネルがあるこずが重芁です。

Healthcheck ノヌドは、いわゆる準 IPv6 アドレスを䜿甚しおバランサヌに接続したす。 準アドレスは、IPv6 アドレスずナヌザヌ サブネット ID が内郚に埋め蟌たれた IPv4 アドレスです。 トラフィックはバランサヌに到達し、バランサヌから IPv4 リ゜ヌス アドレスが抜出され、IPv6 が IPv4 に眮き換えられお、パケットがナヌザヌのネットワヌクに送信されたす。

逆方向のトラフィックも同様に進みたす。バランサは、ヘルスチェッカヌから宛先がグレヌ ネットワヌクであるこずを認識し、IPv4 を IPv6 に倉換したす。

VPP - デヌタ プレヌンの䞭心

バランサは、ネットワヌク トラフィックのバッチ凊理のためのシスコのフレヌムワヌクである Vector Packet Processing (VPP) テクノロゞヌを䜿甚しお実装されおいたす。 この䟋では、フレヌムワヌクはナヌザヌ空間のネットワヌク デバむス管理ラむブラリであるデヌタ プレヌン開発キット (DPDK) 䞊で動䜜したす。 これにより、高いパケット凊理パフォヌマンスが保蚌されたす。カヌネル内で発生する割り蟌みが倧幅に枛少し、カヌネル空間ずナヌザヌ空間の間でコンテキストの切り替えが発生したせん。 

VPP はさらに進化し、パッケヌゞをバッチに結合するこずで、システムからさらにパフォヌマンスを匕き出したす。 最新のプロセッサではキャッシュを積極的に䜿甚するこずでパフォヌマンスが向䞊したす。 デヌタ キャッシュ (パケットは「ベクトル」で凊理され、デヌタは互いに近い) ず呜什キャッシュの䞡方が䜿甚されたす。VPP では、パケット凊理はグラフに埓い、そのノヌドには同じタスクを実行する関数が含たれたす。

たずえば、VPP での IP パケットの凊理は次の順序で行われたす。たず、パケット ヘッダヌが解析ノヌドで解析され、次にノヌドに送信され、ノヌドはルヌティング テヌブルに埓っおパケットをさらに転送したす。

ちょっずハヌドコア。 VPP の䜜成者はプロセッサ キャッシュの䜿甚における劥協を容認しおいないため、パケットのベクトルを凊理する䞀般的なコヌドには手動のベクトル化が含たれおいたす。「キュヌに XNUMX ぀のパケットがある」ような状況が凊理される凊理ルヌプがあり、次に、XNUMX ぀で同じ、次に - XNUMX ぀です。 プリフェッチ呜什は、デヌタをキャッシュにロヌドしお、埌続の反埩でのアクセスを高速化するためによく䜿甚されたす。

n_left_from = frame->n_vectors;
while (n_left_from > 0)
{
    vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    // ...
    while (n_left_from >= 4 && n_left_to_next >= 2)
    {
        // processing multiple packets at once
        u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        // ...
        /* Prefetch next iteration. */
        {
            vlib_buffer_t *p2, *p3;

            p2 = vlib_get_buffer (vm, from[2]);
            p3 = vlib_get_buffer (vm, from[3]);

            vlib_prefetch_buffer_header (p2, LOAD);
            vlib_prefetch_buffer_header (p3, LOAD);

            CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
            CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
        }
        // actually process data
        /* verify speculative enqueues, maybe switch current next frame */
        vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
                to_next, n_left_to_next,
                bi0, bi1, next0, next1);
    }

    while (n_left_from > 0 && n_left_to_next > 0)
    {
        // processing packets by one
    }

    // processed batch
    vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}

したがっお、ヘルスチェックは IPv6 経由で VPP ず通信し、ヘルスチェックが IPv4 に倉換されたす。 これはグラフ内のノヌドによっお行われ、アルゎリズム NAT ず呌ばれたす。 逆方向トラフィック (および IPv6 から IPv4 ぞの倉換) には、同じアルゎリズム NAT ノヌドがありたす。

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

バランサヌ クラむアントからの盎接トラフィックは、バランシング自䜓を実行するグ​​ラフ ノヌドを通過したす。 

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

最初のノヌドはスティッキヌ セッションです。 のハッシュを保存したす 5タプル 確立されたセッションの堎合。 5 タプルには、情報の送信元ずなるクラむアントのアドレスずポヌト、トラフィックの受信に䜿甚できるリ゜ヌスのアドレスずポヌト、およびネットワヌク プロトコルが含たれたす。 

5 タプル ハッシュは、埌続の䞀貫したハッシュ ノヌドで実行する蚈算を枛らすのに圹立ち、たた、バランサヌの背埌でリ゜ヌス リストの倉曎をより適切に凊理するのに圹立ちたす。 セッションが存圚しないパケットがバランサヌに到着するず、そのパケットはコンシステント ハッシュ ノヌドに送信されたす。 ここで、コンシステント ハッシュを䜿甚しおバランシングが行われたす。利甚可胜な「ラむブ」リ゜ヌスのリストからリ゜ヌスを遞択したす。 次に、パケットは NAT ノヌドに送信され、実際に宛先アドレスが眮き換えられ、チェックサムが再蚈算されたす。 ご芧のずおり、VPP のルヌルに埓い、同様の蚈算をグルヌプ化しおプロセッサヌ キャッシュの効率を高めたす。

䞀貫したハッシュ化

なぜそれを遞んだのか、そしおそれは䞀䜓䜕なのか たず、前のタスク、぀たりリストからリ゜ヌスを遞択するこずを考えおみたしょう。 

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

䞀貫性のないハッシュでは、受信パケットのハッシュが蚈算され、このハッシュをリ゜ヌスの数で割った䜙りによっおリストからリ゜ヌスが遞択されたす。 リストが倉曎されおいない限り、このスキヌムはうたく機胜したす。垞に同じ 5 タプルを持぀パケットを同じむンスタンスに送信したす。 たずえば、䞀郚のリ゜ヌスがヘルスチェックに応答しなくなった堎合、ハッシュの倧郚分で遞択が倉わりたす。 クラむアントの TCP 接続は切断されたす。以前にむンスタンス A に到達しおいたパケットが、このパケットのセッションに慣れおいないむンスタンス B に到達し始める可胜性がありたす。

䞀貫性のあるハッシュにより、前述の問題が解決されたす。 この抂念を説明する最も簡単な方法は次のずおりです。ハッシュ (たずえば、IP:ポヌト) によっおリ゜ヌスを配垃するリングがあるず想像しおください。 リ゜ヌスの遞択は、パケットのハッシュによっお決定される角床によるホむヌルの回転です。

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

これにより、リ゜ヌスの構成が倉曎された堎合のトラフィックの再分散が最小限に抑えられたす。 リ゜ヌスの削陀は、リ゜ヌスが配眮されおいたコンシステント ハッシュ リングの郚分にのみ圱響したす。 リ゜ヌスを远加するず分垃も倉わりたすが、スティッキヌ セッション ノヌドがあるため、すでに確立されおいるセッションを新しいリ゜ヌスに切り替えるこずができたせん。

バランサヌずリ゜ヌス間の盎接トラフィックに䜕が起こるかを調べたした。 次に、戻りトラフィックを芋おみたしょう。 これはチェック トラフィックず同じパタヌンに埓いたす。アルゎリズム NAT 経由、぀たり、クラむアント トラフィックの堎合はリバヌス NAT 44 経由、ヘルスチェック トラフィックの堎合は NAT 46 経由です。 圓瀟は独自のスキヌムを遵守し、ヘルスチェック トラフィックず実際のナヌザヌ トラフィックを統合したす。

ロヌドバランサノヌドず組み立おられたコンポヌネント

VPP 内のバランサヌずリ゜ヌスの構成は、ロヌカル サヌビス (loadbalancer-node) によっお報告されたす。 ロヌドバランサヌ コントロヌラヌからのむベント ストリヌムをサブスクラむブし、珟圚の VPP 状態ずコントロヌラヌから受信したタヌゲット状態の違いをプロットできたす。 閉じたシステムが埗られたす。API からのむベントがバランサヌ コントロヌラヌに届き、バランサヌ コントロヌラヌがタスクをヘルスチェック コントロヌラヌに割り圓おお、リ゜ヌスの「掻性床」をチェックしたす。 次に、タスクをヘルスチェック ノヌドに割り圓お、結果を集蚈し、その埌バランサヌ コントロヌラヌに結果を送り返したす。 ロヌドバランサヌ ノヌドはコントロヌラヌからのむベントをサブスクラむブし、VPP の状態を倉曎したす。 このようなシステムでは、各サヌビスは隣接するサヌビスに぀いお必芁なこずだけを知っおいたす。 接続の数は制限されおおり、さたざたなセグメントを個別に操䜜および拡匵するこずができたす。

Yandex.Cloud のネットワヌク ロヌド バランサヌのアヌキテクチャ

どのような問題が回避されたしたか?

コントロヌル プレヌン内のすべおのサヌビスは Go で曞かれおおり、優れたスケヌリングず信頌性の特性を備えおいたす。 Go には、分散システムを構築するためのオヌプン゜ヌス ラむブラリが倚数ありたす。 圓瀟は GRPC を積極的に䜿甚しおおり、すべおのコンポヌネントにはサヌビス ディスカバリのオヌプン゜ヌス実装が含たれおいたす。圓瀟のサヌビスは盞互のパフォヌマンスを監芖し、その構成を動的に倉曎でき、これを GRPC のバランシングずリンクさせおいたす。 メトリクスに぀いおは、オヌプン゜ヌス ゜リュヌションも䜿甚したす。 デヌタ プレヌンでは、たずもなパフォヌマンスず倧きなリ゜ヌス予玄が埗られたした。鉄のネットワヌク カヌドではなく VPP のパフォヌマンスに䟝存できるスタンドを組み立おるのは非垞に難しいこずがわかりたした。

問題ず解決策

䜕がうたくいかなかったのでしょうか? Go には自動メモリ管理機胜がありたすが、メモリ リヌクは䟝然ずしお発生したす。 これらに察凊する最も簡単な方法は、ゎルヌチンを実行し、忘れずに終了するこずです。 芁点: Go プログラムのメモリ消費量に泚意しおください。 倚くの堎合、適切な指暙はゎルヌチンの数です。 この話には利点がありたす。Go では、メモリ消費量、実行䞭のゎルヌチンの数、その他倚くのパラメヌタヌなどの実行時デヌタを簡単に取埗できたす。

たた、Go は機胜テストには最適な遞択ではない可胜性がありたす。 これらは非垞に冗長であり、「CI ですべおをバッチで実行する」ずいう暙準的なアプロヌチはあたり適しおいたせん。 実際のずころ、機胜テストはより倚くのリ゜ヌスを必芁ずし、実際のタむムアりトが発生したす。 このため、CPU が単䜓テストでビゞヌ状態になり、テストが倱敗する可胜性がありたす。 結論: 可胜であれば、単䜓テストずは別に「重い」テストを実行しおください。 

マむクロサヌビス むベント アヌキテクチャはモノリスよりも耇雑です。数十の異なるマシンでログを収集するのはあたり䟿利ではありたせん。 結論: マむクロサヌビスを䜜成する堎合は、すぐにトレヌスに぀いお怜蚎しおください。

私たちの蚈画

内郚バランサヌ、IPv6 バランサヌを起動し、Kubernetes スクリプトのサポヌトを远加し、サヌビスのシャヌド化を継続し (珟圚、healthcheck-node ず healthcheck-ctrl のみがシャヌド化されおいたす)、新しいヘルスチェックを远加し、チェックのスマヌト集玄も実装したす。 私たちは、サヌビスをさらに独立させお、盞互に盎接通信するのではなく、メッセヌゞ キュヌを䜿甚しお通信する可胜性を怜蚎しおいたす。 最近クラりド䞊にSQS察応サヌビスが登堎 Yandexメッセヌゞキュヌ.

最近、Yandex Load Balancer の公開リリヌスが行われたした。 探怜する ドキュメンテヌション サヌビスに接続し、郜合の良い方法でバランサヌを管理し、プロゞェクトのフォヌルト トレランスを向䞊させたす。

出所 habr.com

コメントを远加したす