はじめに
こんにちは。
早稲田大学基幹理工学研究科情報理工・情報通信専攻 修士1年の清水 嶺(@_iy4)と申します。8/17~9/25の6週間、LINEのVerda室ネットワーク開発チームという所でインターンをさせていただきました。インターンでは、VerdaのL4ロードバランサをUDPに対応させるというタスクに取り組んだので、その成果をご紹介したいと思います。
VerdaのLBaaSについて
LINEにおける多くのサービスは、自社のデータセンタ上に構築しているVerdaと呼ばれるプライベートクラウド上で運用されています。Verdaは様々な機能を提供していますが、その中には自社で開発しているLBaaSが含まれています。LBaaSでは
- TCP終端を行わないL4ロードバランサ
- TCP終端を行うL7ロードバランサ
の二つを提供しており、L4ロードバランサは実際にパケットの処理を行うデータプレーンから内製しています。データプレーンはXDPと呼ばれるLinuxの機能を利用して実装されています。Linuxカーネルのプロトコルスタックの中でも、XDPはNICドライバに最も近い場所で動作するため、非常に高速にパケットを処理することが可能です。
LINEのLBaaSについては、以下の資料が非常によくまとまっているので是非ご覧ください。
- https://www.slideshare.net/linecorp/ss-116879618
- https://speakerdeck.com/line_devday2019/software-engineering-that-supports-line-original-lbaas
背景
現在、LINEではサービスをVerdaに順次移行していく段階にあります。その中でも旧来のインフラで用いられていたハードウェアアプライアンスのロードバランサはEOLを迎えようとしており、Verda上のロードバランサに移行されようとしている最中です。そのため、ハードウェアアプライアンスにあってVerdaのロードバランサにない機能を実装する必要がありました。
LINEのサービスの中にはUDPを使用しているものもありますが、Verdaのロードバランサに移行する上で最優先の課題となっていたのは、VerdaのL4ロードバランサがTCPのみにしか対応していないことでした。したがって、Verdaへの移行を進める上でL4ロードバランサのUDPの対応は必要急務だったのです。さらに、現在は仕様策定段階ですが、将来的に広く使われるようになると予想されるQUICやHTTP/3といったプロトコルはUDPの上で動いているため、UDPサポートは今後重要になってくると考えられます。
L4ロードバランサのUDP対応において行った作業
L4ロードバランサのUDP対応においては主に、
- データプレーンでのUDPパケット処理
- データプレーンのベンチマーク基盤のUDP対応
- Path MTU Discoveryの実装
- ロードバランサのコントローラーの実装変更
の作業が必要でした。ここでは各作業の詳細について詳しく説明します。
1. データプレーンでのUDPパケット処理
VerdaのロードバランサはTCPの場合、以下のような手順でパケットを処理します。
- クライアントがロードバランサのIPアドレス(Virtual IP)を指定してパケットを送信する。
- ロードバランサはパケットのヘッダ情報を元にハッシュ値を計算し、Maglev Hashingと呼ばれるアルゴリズムで転送先のサーバー(Real Server)を決定する。
- クライアントが送信したパケットを、転送先のサーバーのアドレスが入ったIPヘッダでカプセル化し配送する。(IPIPトンネリング)
- パケットを受け取ったサーバーは、カプセル化されたIPヘッダを外した後、Linuxのネットワークプロトコルスタックに流す。
- クライアントにレスポンスパケットを返す。このとき、レスポンスパケットはL4ロードバランサを経由しないで直接クライアントに渡される。(L3DSR)
この中でも、実際にデータプレーンが担うのは2, 3になります。それゆえ、UDPに対応するにはUDPヘッダの情報を採取し、ハッシュ値を計算するような処理を追加する必要がありました。また、L4ロードバランサには、eBPF Map経由で各種メトリクスをPrometheus経由で転送する仕組みも存在していますが、UDP対応にあたって、必要なメトリクスの追加も行いました。
2. データプレーンのベンチマーク基盤のUDP対応
VerdaのL4ロードバランサは専用のベンチマーク基盤が用意されていて、データプレーンに変更が加わる度に自動的に計測され、結果のプロットがGitHubのPRに投稿されます。
このベンチマークにUDPのシナリオを追加して、TCPの場合とUDPの場合のパフォーマンスを並行してグラフに描画するようにしました。具体的には以下のようなものになります。
凡例について、no_flagがついているものは単一のVirtual IPに対してパケットを投げたときのもので、単一フローに対するベースラインの性能を表しています。対して、multi_vipがついているものは複数のVirtual IPに対してパケットを投げたときのものであり、マルチフロー転送性能時の性能を表しています。テストシナリオについては以下のようになっています。
- Max Throughput
- 規格上の伝送レートでパケットをロードバランサに投げ続け、どれほどのスループットが出るのかを計測する。
- Zero-Packet-Loss
- 初期時は規格上の伝送レートでパケットを送信し、0.0001%以上のパケットロスがあれば伝送レートを下げ、パケットロスが0.0001%以内に抑えられているのであれば伝送レートを上昇させるような二分探索を行ってスループットを計測する。
このベンチマーク環境については、以前のLINE Developer Meetupの資料で説明されているので、詳しく知りたい方は以下の資料をご覧ください。
3. Path MTU Discovery(経路MTU探索)の実装
一般に、ネットワークノード間のパスにMTU(Maximum Transmission Unit)が設定されており、これを超えるサイズのパケットを送信することができないという決まりがあります。これを超えるサイズのパケットを流すには、エンドノードまたは中間ノードでパケットを分割(フラグメント)し、到着したノードで再構成するという処理が必要となってきます。
L4ロードバランサは
- クライアントからL4ロードバランサ
- L4ロードバランサからReal Server
の2本のネットワークパスを持っています。ここで、両方のネットワークパスがMTU1500になっている状況を想定してみましょう。このとき、L4ロードバランサからReal ServerまでのネットワークパスはIPIPカプセル化が行われた状態でパケットが送られるので、クライアントからL4ロードバランサまでのパスよりも実質的に20バイト少ないパケットしか送れない状況であることが分かります。なぜなら拡張フィールドが存在しない場合、IPヘッダは20バイトだからです。つまり、クライアントからL4ロードバランサは最大1480バイトのL3パケットしか送れません。それでも送りたい場合、IPv4でDF(Don't Fragment)フラグが立っていない場合はロードバランサで上述したようなパケットのフラグメントを行う必要があります。なお、IPv6の場合はこのようなフラグメントが中継ノードで行われないことは仕様で決まっています。
Verdaのロードバランサにはフラグメントの機能が実装されておらず、IPIPカプセル化を行った結果MTUを超えてしまう場合はパケットを落とすようになっていました。そのため、TCPを用いる際、LINEのロードバランサにおいては、以下の図のように、TCPのハンドシェイク時にMSSオプションを書き換えてパケット分割が経路中で起きない程度の大きさに明示的に指定し、制限する方法を用いていました。
従来のL4ロードバランサはTCPしかサポートしていなかったため、この方法で問題ありませんでした。しかし、UDPにはMSSオプションのような機能がないので、この方法が使えません。この場合は、ICMP Too Bigパケットを用いるPath MTU Discovery(経路MTU探索/PMTUD)を用いて対処します。PMTUDの具体的な流れは以下の図のようになります。
- クライアントが1500バイトのL3パケットを送信する。
- L3パケットのサイズが1480バイトを上回っているのでL4ロードバランサからサーバーへのパスにパケットを流すことが出来ない。そのため、L4ロードバランサは送ることができる最大のパケットサイズが1480バイトであることをクライアントに知らせるため、ICMP Too BigパケットにMTUを設定しクライアントに向けて送る。
- ICMP Too Bigパケットを受け取ったクライアントはMTUを超えないようにパケットを分割し、L4ロードバランサに向けて送出する。
今回のインターンではこのPMTUDにおいて必須となる、パケットサイズを判定してICMP Too Bigを送信する機能をXDP上で実装しました。
4. コントローラーの実装変更
VerdaのLBaaSは、ユーザー毎にロードバランサのインスタンスが作成されるのではなく、共有のロードバランサインスタンスにユーザーがリクエストした設定を反映するという形式を取っています。この設定を反映する役割を担うのはコントローラと呼ばれるREST APIサーバーで、ユーザーが設定を含むリクエストを投げると、ロードバランサのインスタンスに設定が反映されます。ロードバランサのインスタンスはバージョンによってサポートしている機能に差異があるため、コントローラはユーザーの設定内容を見て、要求する機能に合致する適切なインスタンスを選択する必要があります。
今回のタスクでは、「UDPをサポートしているロードバランサのインスタンス」を選択するような機能を追加しました。
5. QUICのベンチマーク
QUICは既存のHTTPのオーバーヘッドとなっていたTCP+TLSの処理を解消するために開発された新しいプロトコルで、HTTP/3に採用されています。このプロトコルはUDPの上に構築されています。そのため、今回のインターンで開発したUDPのロードバランサを用いてパフォーマンスを測定してみました。測定に使用したマシンのスペックは以下のようになります。
ロードバランサ
- CPU: Xeon E5-2630 v4 2.20GHz
- Memory: 64GB
- NIC: ConnectX-4 Lx (25G)
クライアント
- CPU: Xeon Gold 6150 2.70GHz
- Memory: 128GB
- NIC: ConnectX-4 (100G)
サーバ
- CPU: Xeon E5-2630 v4 2.20GHz
- Memory: 128GB
- NIC: Intel XL710 (40G)
今回の測定では、mvfst1と呼ばれるFaceBook社がオープンソースとして公開しているQUICのライブラリを用いたベンチマークツールを自作2しました。
mvfstにはベンチマークツールが付属していますが、サーバからクライアントの下りトラフィックの計測にしか対応していませんでした。今回はL3DSRのLBを経由した上りのトラフィックを計測したかったため、ツールを自作しました。
結果は以下のようになりました。
今回の計測ではまずベースラインとなるパフォーマンスの数字を知るためにiperf3を利用した計測を最初に行い、QUICのパフォーマンスとの比較を行いました。パフォーマンス計測はクライアント-バックエンド間と、間にロードバランサを挟んだケース両方で計測しました。
また、TCP/UDP/QUICすべてのプロトコルにおいてフェアな比較をするためにTSO/GSO/LRO/GROといったセグメンテーションオフロードの機能はクライアント/サーバ共にOffにしました。また、IPパケットのサイズもQUICの仕様4に合わせて1252byteに統一しました。
結果としてはベースラインのTCP/UDPの約4Gbpsのスループットと比較してQUICのパフォーマンスは約900Mbpsと非常に低いという結果になりました。QUICはUDPベースなので、UDPのスループットからQUICのスループットを引いた約3.1GbpsがQUICのオーバーヘッドということになります。この内訳を計測するには至りませんでしたが、おそらくクライアントとサーバでの暗号化/復号処理によるところが大きいのではないかと予想しています。
また、ロードバランサを挟んだ場合のスループットに関しては多少の差が出る程度という結果になりました。もっとも、この計測で得られた数字はロードバランサで出せる最大スループットを大きく下回っているため、ロードバランサの計測という意味では上記のベンチマーク基盤での計測の方が参考になりそうです。しかし、こういったサーバグレードマシンでのQUICのパフォーマンス計測に関しては情報が少ないと思いますので個人的には興味深い結果を出せたのではないかと思います。
総括
今回のインターンではVerdaのL4ロードバランサのUDP対応を行いました。現在はLINEではTCPと比べるとUDPを用いるプロダクトは多くないものの、現在標準化が進められている、UDPをベースとしたプロトコルであるQUICやHTTP/3が広く使われるようになってくると、UDPのロードバランシングの重要性は増してくるのではないかと感じています。今後の本命はQUICであると考えられるので、QUICのロードバランシングといった機能も今後重要になってくるのではないかと思います。
感想
今回のインターンは昨今の状況を鑑みたフルリモートという形で開催されました。そのため、社員さんや他のインターン生との対面での交流というのは叶いませんでした。しかし、リモートであっても困ることなく働くことが出来る環境が用意されていて非常に快適でした。また、技術的にも私はパケット処理やXDPなどの経験がありませんでしたが、メンターさんやチームのメンバーの社員さん達に色々とサポートしていただける環境だったお陰でこういったチャレンジングなタスクに取り組めることが出来たと感じました。在宅ながら非常に濃密な夏になったと思います。本当にありがとうございました。
注釈
- mvfst: https://github.com/facebookincubator/mvfst
- ベンチマークツール: https://github.com/Shikugawa/mvfst-quicbench/tree/master/quic/samples/bench
- iperf: https://iperf.fr/
- draft-ietf-quic-transport-31: https://tools.ietf.org/html/draft-ietf-quic-transport-31#section-14