高頻度データ伝送におけるQUIC適用の検討

f:id:aptpod_tech-writer:20200117184938j:plain 先進技術調査グループのリサーチエンジニアの酒井 (@neko_suki)です。

先進技術調査グループでは、新しいトランスポートプロトコルのQUICの製品への適用を検討しています。今回の記事では、自社が主に扱う高頻度なデータの伝送における課題のひとつをQUICを適用したらどうなるかを評価してみました。

目次は以下の通りです。

QUICとは

QUICとは、Googleが提案・実装をし、現在IETFで標準化が行われているプロトコルです。(区別のため、前者はgQUIC、後者はiQUICと呼ばれています)。2020年の中頃にはRFCが発行される予定です。

QUICはUDPベースの信頼性のある接続を提供するトランスポートプロトコルです。QUICではコネクション上に仮想的なストリームを生成して通信を行います。

今回は高頻度なデータの伝送における課題のひとつであるHoL Blocking という課題について、QUICを適用して課題の解決が可能かどうかを確認します。

Head of Line (HoL) Blocking とは

TCPは順序を保証します。そのため、以下の図のようにパケットロスが発生すると、サーバアプリケーションが後続のデータを受信するタイミングに遅延が発生するという課題がありました。

f:id:aptpod_tech-writer:20200109185617p:plain
TCPにおけるHoL

QUICでは異なるストリーム間の順序保証を行わずにデータを送信することができます。(ただし、同一ストリーム内では順序保証がされます)。下の図のようにUDPのパケットがロスしても、サーバアプリケーションは別のストリームで送信されているデータをHoL Blockingによる遅延の影響なく受信することが期待できます。

f:id:aptpod_tech-writer:20200109185740p:plain

実験内容

実験は、高頻度なデータの塊をクライアントからサーバに伝送するケースを想定します。

送信するデータは仮に1unit (データの単位)を8byteとします。これを1000 unit/secで送信します。そのために1msec毎に1unitのデータをクライアント側で生成します。

クライアント-サーバ間の送信遅延を評価するために、データがクライアントで生成された時刻とサーバ側で受信した時刻の差分を遅延時間として定義します。

intdashでは、IPやTCPヘッダのオーバーヘッドを低減するために、flushという一定期間のユニットをバッファリングして送信する仕組みを導入しています1

f:id:aptpod_tech-writer:20200109181319p:plain
flush 構造

なので、10個の連続したデータを一つの塊として送信します。以降、このバッファリングしたデータ単位を flush と呼びます。

以下の図のように、10個の連続したデータを1個のflushとして、一つのQUICパケットおよびUDPパケットに格納します。

f:id:aptpod_tech-writer:20200117175950p:plain:w300

一つの塊に含まれるデータの到達遅延は、生成時刻が古いデータから順に、片道遅延+9 msec+α (αはタイミングに依存), 片道遅延 + 8msec + α, ... 片道遅延 + 0msec + αで到達することが予想されます。

今回の実験ではHoL Blockingの影響が発生しないことを確認するために、1flush毎に一つのQUICストリームを作成してデータを送信します。 これによって、特定のUDPパケットがロスしても他のパケットの受信には影響が出ないことが期待されます。

f:id:aptpod_tech-writer:20200109190304p:plain

評価はネットワークのエミュレーション環境で行います。HoL Blockingの影響を受けずにデータを送信できることを確認するためにパケットロス率は2%としています。また、モバイル環境を想定して往復遅延50msec(片道25msec) を設定しました。

参考までに、QUICの実装はquic-go を用いています。

実験結果

以下の図では、送信したデータそれぞれに対して時系列に遅延時間として「ユニットの受信時刻 - ユニット生成時刻」を時系列にプロットしています。縦軸が遅延時間 (msec) 横軸は、時系列に10秒間送信した10,000個のデータを表しています。

f:id:aptpod_tech-writer:20200109192828p:plain

片道の遅延が25msecかつ1flushで10msec分のデータを溜め込むため、パケットロスが発生していない場合は、25msec~35msecの範囲におおむねデータが収まります。図を見ると多くの場合にそうなっていることが確認できます。また、パケットロスが発生しているときのデータが、その範囲から飛び出ていることが見て取れます。

定量的な評価のため、パーセンタイルを確認してみます。ここではベースラインとしてロス率が0%で実験をした時の値も載せています。

パーセンタイル ロス率2%の時の遅延 (msec) ロス率0%の時の遅延 (msec) 2%の時の遅延 - 0% の時の遅延 (msec)
98% 85.81 35.83 49.98
97% 49.50 35.66 13.84
95% 43.10 35.53 7.57
90% 38.31 35.10 3.21
50% 32.63 31.11 1.52

98パーセンタイルの時には、パケットロスがない時と比較して、49.98 msecの遅延が発生しています。一方で、97パーセンタイルになると13.84 msecまで縮まります。95, 90, ... 50と値を小さくしていくと、パケットロスがない時との差分はほぼ無視できるレベルまで縮まることが確認できます。

さらに、生データを詳細に分析してみます。

1つのUDPパケットが、パケットロスせずに1flush分のデータを送った場合の遅延時間「ユニットの受信時刻 - ユニット生成時刻」は以下のようになります。

flush内に含まれるデータのインデックス ユニットの受信時刻 - ユニット生成時刻
1 35.81
2 34.87
3 33.79
4 32.79
5 31.79
6 30.86
7 29.74
8 28.76
9 27.76
10 26.95

10msec分のデータがバッファされるので、最もインデックスが古いデータが片道遅延 25msec + 11msec、最も新しいデータがほぼ片道遅延25msec+2msec 程度になっていることがわかります。

データを詳細に分析した結果、パケットロスしたと思われる1flush分のデータは遅延時間が100msec近い値になることを確認しました。遅延が増加した状況は1flush=10個のデータ分続きます。そして、その次のflushのデータは正常な値に回復します。

相対的なデータのインデックス ユニットの受信時刻 - ユニット生成時刻
前のflushの最後のデータ 27.27
1 103.74
2 102.76
3 101.79
4 100.68
5 99.77
6 98.72
7 97.74
8 96.58
9 95.73
10 94.75
次のflushの最初のデータ 36.25

遅延が80msec 以上だったデータをこのパターンに含まれているとすると、10000個あるデータの中で、210個がこのパターンに該当しました。これはおおむね全体の2%でありパケットロスを設定した値と同じになります。

なので

期待通りにHoL blockingの影響を回避してデータを受信できていることが確認できた

と言えそうです。

まとめ

本記事では、自社が扱う高頻度なデータの伝送における課題のひとつであるHoL Blocking という課題について、QUICを適用したらどうなるかを評価してみました。HoL Blocking の回避の観点だとQUICの適用は有効であると言えそうです。

先進技術調査グループでは今後もQUICの検討を進めていきます。

QUICなどの最先端の通信・ネットワークプロトコル技術を用いた研究開発・製品開発に興味がある方は、ぜひ以下の採用ページへのアクセスをお願いします!

採用情報:https://www.aptpod.co.jp/recruit/

参考文献


  1. White Paper: iSCP (intdash Stream Control Protocol) https://www.aptpod.co.jp/basetech/05.iscp.pdf