
XDP/eBPFを使用した、Linux向けの水平方向にスケーラブルなDirect Server Returnレイヤ4ロードバランサー
このREADMEは最近の変更を反映するために現在更新中です。一部の情報は現在のコードベースを反映していない可能性があります。このコードのイテレーションはまだ実戦投入準備ができていません。本番環境ではv0.2リリースを使用してください
Linux向けの、XDP/eBPF を使用した水平スケーラブルなDirect Server Return(DSR)レイヤ4ロードバランサー(L4LB)です。
これが役に立つと思われる場合、またはご質問・ご提案がある場合は、[email protected] までご連絡いただくか、GitHubのissueを起票してください。
IPv6およびレイヤ3(別名トンネリング)での配信に対応しました! XVSライブラリはこれらの機能を含むように更新され、ネットワーク名前空間からヘルスチェックを実行する必要もなくなり、コードがかなり簡素化されました。これにより、すべてのバックエンドがロードバランサーとVLANを共有するという要件は終了します。
現在のコード上の制約により、サービス単位でのトンネリング有効化はサポートされていません。-tunnel オプションを使用すると、単一の方式(IP-in-IP、GRE、FOU、またはGUE)でレイヤ3トンネリングをグローバルに有効にできます。今後、サービスレベルでトンネリングを設定できるようにコードが更新される予定です。
レイヤ2ロードバランシングは引き続きサポートされます。このプロジェクトを開始した主な理由は、FacebookのKatran ロードバランサーがレイヤ2をサポートしていなかったためです。
サンプルのIPv6/L3設定ファイル が含まれています。より詳細なドキュメントは後日公開予定です。
VC5は、レガシーなハードウェアアプライアンスの代替として動作するように設計されたネットワークロードバランサーです。仮想IPアドレス(VIP)を持つサービスを、バックエンド(「実」)サーバーのセットに分散できます。実サーバーはサービス自体を実行するか、別のサーバー層のプロキシとして動作します(例: アプリケーション層の判断が必要な場合に、レイヤ7 HTTPルーター/SSLオフロードとして機能するHAProxy)。唯一の要件は、各実サーバーのループバックデバイスにVIPを設定することです(例: ip addr add 192.168.101.1/32 dev lo)。
サービスと実サーバーは、ヘルスチェック定義とともに設定ファイルで指定されます。バックエンドサーバーがチェックに合格し、サービスを提供するのに十分な数が利用可能になると、仮想IPアドレスがBGPを介してルーターにアドバタイズされます。
レイヤ2とレイヤ3の両方でのトラフィック配信がサポートされるようになりました。レイヤ2配信では、実サーバーがロードバランサーとVLANを共有する必要があります。配信するパケットを受信すると、ロードバランサーはパケット内のイーサネットハードウェアアドレスを更新し、宛先に実サーバーのMACアドレス、送信元に自身のMACアドレスを使用して、適切なインターフェースを介してパケットを転送します。パケットがVLANタグ付けされている場合は、802.1Q VLAN IDも更新します。
レイヤ3配信では、パケットを実サーバーのIPアドレス宛てのトンネリングプロトコルでカプセル化し、ルーターを介して転送する必要があります(サーバーとロードバランサーがVLANを共有している場合を除く)。カプセル化されたパケットがネットワークの最大転送サイズを超える場合は、適切なMTUに関するアドバイスとともにICMPメッセージが送信元に送信されます。バックエンドサーバーはパケットをデカプセル化するだけでよく、ロードバランサーとの双方向トンネリングは不要です。
10Gbit/sのネットワークインターフェースを備えた1台のサーバーで、ほとんどのインターネットトラフィックの非対称性により、100Gbit/sを超えるエグレス帯域幅のHTTPサービスをサポートできるはずです。小規模なサービスの場合、控えめな仮想マシン1~2台で、数Gbit/sのエグレストラフィックを生成するサービスを処理できるでしょう。
1つのインスタンスで不十分な場合は、ルーターのECMP機能を使用してサーバーを追加し、容量を水平に拡張(および冗長性を提供)できます。802.3adボンドインターフェースと802.1Q VLANトランキングがサポートされています(examples/ ディレクトリを参照)。
カーネルモジュールや複雑なセットアップは不要ですが、最高のパフォーマンスを得るには、XDPネイティブモードをサポートするネットワークカードドライバー(例: mlx4、mlx5、i40e、ixgbe、ixgbevf、nfp、bnxt、thunder、dpaa2、qede)を推奨します。完全なリストは The XDP Projectのドライバーサポートページ で入手できます。
最良の結果を得るには、irqbalanceを無効化/アンインストールしてください。
バランサーに渡すプライマリIPを選択する必要があります。これはBGPルーターIDに使用されます。
単一のタグなしイーサネットインターフェースを備えたサーバーでの簡単な例:
apt-get install git make libelf-dev golang-1.20 libyaml-perl libjson-perl ethtool(またはお使いのディストリビューションの同等のパッケージ)ln -s /usr/lib/go-1.20/bin/go /usr/local/bin/go(GoバイナリがPATHに含まれていることを確認してください)git clone https://github.com/davidcoles/vc5.gitcd vc5/cmdcp config.sample.yaml config.yaml(要件に合わせてconfig.yamlを編集してください)make(libbpf ライブラリを取得し、バイナリとJSON設定ファイルをビルドします)./vc5 10.1.10.100 config.json eth0(お使いのサーバーのIPアドレスとイーサネットインターフェースに合わせて変更してください)ip addr add 192.168.101.1/32 dev lo)最新のGithubリリース(x86-64用にコンパイル済み)のバイナリを使用する方がほぼ間違いなく簡単です。これは本番環境でテストされているため信頼できるはずです。タグ付きリリースのconfig.plスクリプトを使用して、設定がこのバージョンと互換性があることを確認してください(もちろん、お好みで独自のJSON設定をビルドすることもできます)。
YAML設定ファイルを更新してJSONを再生成する場合(make config.json)、プロセスにSIGINT(Ctrl-C)またはSIGUSR2を送信することで新しい設定をリロードできます。SIGQUIT(Ctrl-\) またはSIGTERMを送信すると、プロセスはBGP接続を正常にシャットダウンして終了します。
2つのインターフェース(私のテストサーバーでは10Gbps Intel X520)で構成されるLACPボンドイーサネットデバイスを使用し、ネイティブXDPドライバーモードを有効にし、タグ付きVLANを使用するより複雑な例:
config.yaml のvlansエントリ:
vlans:
10: 10.1.10.0/24
20: 10.1.20.0/24
30: 10.1.30.0/24
コマンドライン:
./vc5 -n 10.1.10.100 config.json enp130s0f0 enp130s0f1
バイナリは、設定ファイル内のVLANプレフィックスに含まれるIPアドレスを持つデバイスを探すことで、VLANインターフェースを検出します。個別のタグなし物理インターフェースを使用する場合は、eBPFコードが各インターフェースにロードされるように、コマンドラインですべてのインターフェースを列挙するだけで、追加設定なしで透過的に動作するはずです。
接続状態はコア単位で追跡されるため(BPF_MAP_TYPE_LRU_PERCPU_HASH)、LACPトポロジーが変更されたときにスイッチが別のインターフェースを選択した場合でも、RSS(Receive Side Scaling)がフローのパケットを常に同じCPUコアにルーティングするようにしてください。irqbalanceを無効にし、各インターフェースのチャンネル設定が同じであること(ethtool -l/-L)、およびRSSフローハッシュのインダイレクションが一致していること(ethtool -x/-X)を確認してください。
このセットアップは、バックエンドサーバーのセットへの長時間実行接続(例: -t オプションを付けたiperfを使用)を開始し、設定ファイル内のIPアドレスの後にアスタリスクを付けて選択したバックエンドを無効化して、ロードバランサー上でどのインターフェースがフローを受信しているかを特定し(例: watch -d 'cat /proc/interrupts | grep enp130s0f' で急速に増加するIRQカウンターを探す)、その後このインターフェースをLACPから外す(ifenslave -d bond0 enp130s0f0)ことでテストできます。フローがもう一方のネットワークインターフェースに移動しても、同じコアに到達するのが確認できるはずです。
複数のサブネットのバックエンドを使用する場合、最高のパフォーマンスを得るには、すべてのVLANが単一のトランクインターフェース(物理インターフェースが複数ある場合はLACPボンド)にタグ付けされ、サブネット/VLAN IDマッピングが設定ファイルの vlans セクションで指定されていることを確認してください。
これが不可能な場合(たとえばvSphereでトランクインターフェースを作成するのは簡単ではありません)、各サブネットを異なるタグなしインターフェースに割り当てることができます:
./vc5 10.1.10.100 config.json eth0 eth1 eth2
使用されている概念の良い要約は、Patrick Shuff氏の「Building a Billion User Load Balancer」トーク と Nitika Shirokov氏のKatranトーク で説明されています。
基本的なWebコンソールとPrometheusメトリクスサーバーが含まれています: 
ロギング用の実験的なElasticsearchサポート(クラスターに直接送信するため、システムログをスクレイピングする必要はありません)が追加されました。バックエンドサーバーへのすべてのプローブがログに記録されるため、ダウンした場合に返されたエラーを正確に確認でき、その他のさまざまな状態も確認できます。これには多くの改良と、ログパラメーターの名前のより適切な設定などが必要ですが(何か洞察があればご連絡ください)、システムで何が起こっているかについての優れた洞察が得られるようになるはずです。私の非常に不器用な最初のKibanaダッシュボード作成の試みを例として示します: 
これは主にIcecastバックエンドサーバーを使用してテストされ、クライアントは低ビットレートと高ビットレートのストリーム(48kbps - 192kbps)を混在して取得しています。
XDP汎用ドライバーを使用するVMWareゲスト(4コア、8GB)は、ロードバランサーを通過する100K同時クライアント、380Mbps/700Kpps、およびバックエンドからクライアントへの直接トラフィック8Gbpsをサポートできるようです。
単一の(非仮想化)Intel Xeon Gold 6314U CPU(2.30GHz、32物理コア、ハイパースレッディング有効で64論理コア)とIntel 10G 4P X710-T4L-tイーサネットカード上で、2Gbps/3.8Mppsのイングレストラフィックと46.5Gbpsのエグレスで700Kストリームを実行できました。サーバーは90%以上アイドル状態でした。残念ながら、より多くのクライアント/サーバーを作成するためのリソースはありませんでした。
動作モードは、シンプル、VLAN、マルチNICベースの3つがあります。シンプルモードでは、すべてのホストがロードバランサーのプライマリアドレスと同じサブネット上にある必要があります。VLANモード(YAML/JSON設定ファイルの "vlans" セクションでエントリを宣言することで有効化)では、サーバーエントリがVLAN/CIDRサブネットエントリと一致する必要があります。VLANタグ付きインターフェースはOSで作成し、サブネット内のIPアドレスを割り当てる必要があります。マルチNICモードでは、サブネットはVLANと同じ方法でIDが付けられますが、適切に設定されたインターフェースからトラフィックを送信するために bpf_redirect() が使用されます(VLAN IDを変更して XDP_TX を使用する代わりに)。
VLANモードでは、ロードバランサーへのすべてのトラフィックはタグ付きVLAN上にある必要があります(802.1Qのプッシュまたはポップはまだ行われません)。