マルチパス
mqvpn は Multipath QUIC を使用して、複数のネットワークパスで同時にトラフィックを転送します。これにより以下が可能になります:
- シームレスなフェイルオーバー — あるパスがダウンしても、残りのパスでトラフィックが継続します。切り替え中に短い遅延が発生する場合があります。
- 帯域集約 — 複数インターフェースの帯域幅を組み合わせます(例: WiFi + LTE)。複数の同時フローがある場合に最も効果的です。単一の TCP フローで集約を行いたい場合はhybrid modeを使用してください。
マルチパスのセットアップ
CLI
--path で各ネットワークインターフェースを指定します:
sudo ./build/mqvpn --mode client --server 203.0.113.1:443 \
--auth-key <key> --path eth0 --path wlan0設定ファイル
[Multipath]
Scheduler = wlb
Path = eth0
Path = wlan0TIP
--path フラグや Path エントリを指定しない場合、mqvpn はデフォルトインターフェースを使用します(シングルパスモード)。
スケジューラ
スケジューラはパケットをパス間でどのように分配するかを決定します。mqvpn は以下のスケジューラをサポートしています:
WLB(Weighted Load Balancing)— デフォルト
WLB は、パス重み付けとフロー考慮スケジューリングを組み合わせた方式です:
- ロス率・RTT・cwnd などの実測値から各パスの推定スループットを算出し、トラフィック分配比率として使用
- deficit ベースの WRR でアクティブなパスへトラフィックを分配
- VPN トンネル内の並び替えを抑えるため、内部 TCP フロー(flow hash)をパスにピン留め
- ピン留め先が一時的に cwnd ブロックされた場合は、恒久的な再ピン留めなしで spillover
- 非 Datagram 系パケットや、有効なスケジューラ対象パスがない場合は MinRTT にフォールバック
--scheduler wlbWLB UDP Pin(wlb_udp_pin)
WLB の派生で、通常の WLB が TCP コネクションを一本のパスに固定するのに加えて、 UDP コネクションも一本のパスに固定するスケジューラです。
--scheduler wlb_udp_pinトンネル内に自前で順序付けを行う UDP フローがあって、通常の wlb では スループットが伸びない、という場面で試す価値があります。仕組みとしては、 mqvpn が遅延差のある複数パスにパケットを散らすと、順序を見ている内側の プロトコルが並び替えをロスと誤認して速度を落としてしまうことがあります。 wlb_udp_pin は同じコネクションのパケットを 1 本のパスに揃えるので、この 並び替えが起こりません。
ただし、内側が単一コネクションの場合、wlb_udp_pin でも 1 本のパス分の 帯域までしか出ません。単一のシーケンス空間で動くプロトコルでは、複数パスで 帯域を合算するには内側自体のマルチパス対応が必要だからです。それでも、 wlb で散らして並び替えで自壊するより「安定して 1 パス分が出る」方が 実用的、というのが wlb_udp_pin を選ぶ意義です。
逆に、内側 UDP が並び替えを許容するなら通常の wlb の方が向いています。 複数パスに散らした方が回線を合算した帯域を使い切れるためです。また実装上、 wlb_udp_pin で追跡できる UDP コネクション数には上限があり、毎秒大量の 短命フローを生む環境では古いフローの追跡がこぼれて固定の効果が薄くなる ので、そうしたケースも wlb の方が無難です。
順序を気にする UDP のスループットが wlb で出ないと感じたら wlb_udp_pin を試す、それ以外なら wlb のまま、という使い分けで OK です。
MinRTT(Minimum Round-Trip Time)
MinRTT は各パケットを現在の RTT が最も低いパスで送信します。よりシンプルですが、利用可能な帯域幅を効率的に活用できない場合があります。
- レイテンシを最適化(スループットより優先)
- シンプルなアルゴリズム、予測可能な動作
--scheduler minrttBackup FEC (experimental)
通常のトラフィックを AVAILABLE パスに送り、FEC リペアシンボルを STANDBY パスに送ります。プライマリリンクがロスしやすく(例: 不安定な WiFi)、 スタンバイがより信頼できる(例: LTE)構成向けに設計されています。
--scheduler backup_fec使うべき場面: ロスの多い環境での WiFi+LTE マルチパス。スタンバイパス上の リペアシンボルにより、再送 RTT を待たずにプライマリパスのロスを即座に回復 できます。
使うべきでない場面:
- シングルパス構成(スタンバイパスがない = リペアシンボルの送り先がない)
- 帯域集約を狙う高帯域シナリオ(代わりに
wlbを使用) - 両端点が mqvpn 0.4.0 以上で、FEC ビルド (
-DXQC_ENABLE_FEC=ON -DXQC_ENABLE_XOR=ON) が有効である必要があります
チューニング: デフォルトは XOR FEC でブロックあたり約 33% のオーバーヘッド (src/mqvpn_scheduler.h の MQVPN_FEC_* マクロ参照)。本実験リリースでは FEC パラメータの CLI フラグは公開されていません。
性能: ロス率 1%〜10% における WLB との実測スループット比較は 週次ベンチマークを参照。
スケジューラ選択指針
| シナリオ | 推奨 |
|---|---|
| 一般的な用途、帯域集約 | WLB + hybrid mode |
| 単一パスでの配送が必要な内部 UDP | wlb_udp_pin |
| レイテンシ重視のアプリケーション | MinRTT (帯域集約とのトレードオフだが、ライブ配信などでは冗長モードの利用を検討してください。) |
| 品質の悪い回線の組み合わせ | MinRTT + hybrid mode(場合に応じて Reinjection や Reorder buffer の併用も検討) |
| ロスの多いプライマリ + 信頼できるスタンバイ(実験的) | backup_fec |
Reinjection(投機的複製)
Reinjection は、選んだパケットのコピーをもう 1 本のパスにも送る機能です。 帯域を少し余分に使う代わりに、パケットロスや回線の急な不調があっても トンネルが滑らかに動き続けるようになります。デフォルトは無効で、 スケジューラ設定とは独立に使えます。オリジナルは通常どおり送られ、 コピーは必ずオリジナルとは別のパスに送られます。
Ref: XLINK (SIGCOMM 2021)
[Multipath]
Reinjection = deadline # off | deadline | idle| モード | 何をコピーするか | 用途 |
|---|---|---|
deadline | ストリームレーン(TCP 側)のうち、届いた確認が取れないまま遅れ気味になっているデータと、不調と判定されたパスに送った全データ | TCPをQUIC Streamで転送するハイブリッドモードのトンネル向けの保険。普段は何もせずコストもほぼゼロで、回線が突然不調になった瞬間の引っかかりを最小限に抑えます |
idle | トンネルが他に何も送っていない暇な瞬間の、直近の未確認ストリームデータ(TCP 側のみ) | SSH やブラウジングなどで、たまに起きる引っかかりを低コストで減らします。チューニング不要 |
そもそもなぜ引っかかるのか: 回線が不調になっても、新しいデータは スケジューラが健全な回線へ流します。しかし不調になった回線に送信済みだった データは回復を待つ必要があり、順序どおりに届ける仕組みのため、健全な回線で 先に届いた後続データもアプリに渡せず足止めされます(マルチパスの head-of-line blocking)。無音で死んだ回線は最悪数百 ms のタイムアウトまで 検出できないため、最悪条件ではこの足止めが 1 秒近くになります。deadline は 遅れたデータをすぐ健全な回線にも送り直すことで、この足止めを削減します。
deadline モードのチューニング(デフォルト値):
ReinjectionSrttFactorPct = 110 # 最小往復時間(min_srtt)の 1.1 倍を超えて未確認ならコピー(100–1000)
ReinjectionHardDeadlineMs = 500 # 待ち時間の上限 ms(1–60000)
ReinjectionDeadlineLowerBoundMs = 20 # 待ち時間の下限 ms(1–60000。上限を超える設定は上限に切り詰め)注意:
- Reinjection は送信側の機能です。各側の設定は自分が送信するトラフィックを 保護するため、ダウンロードを保護するにはサーバ側で有効にします (アップロードはクライアント側)。
- パスごとの複製送信バイト数は control API の
get_status応答のreinject_tx_bytesで確認できます。 - 2 本以上のアクティブパスが必要です(1 本のときは自動的に何もしません)。
冗長モード
冗長モードは、送信する UDP パケットのコピーを複数の回線で同時に送ります。 1 本の回線が数秒途切れても、たいていは他の回線のコピーでライブ配信が続きます。 デフォルトは無効です。
[Multipath]
Redundant = true
RedundantPorts = 4200 # 任意: 宛先がこのポートの UDP だけ複製
CC = bbr # 冗長モードでの推奨Android では Redundant Mode スイッチをオンにします(ポートの指定は Redundant Ports 欄)。オンにすると、アプリは CC = bbr も使います。
- 使いどころ: スマホ回線を使った SRT などのライブ配信(特にレイテンシ 設定が短いとき)や、数秒ずつ途切れる回線。
- コスト: 対象のトラフィックのデータ使用量は、2 本なら最大 2 倍、 3 本なら最大 3 倍になります。
RedundantPortsに配信のポート (例:4200、または4200,9000のようにカンマ区切りで最大 16 個)を 指定すると、その分だけに絞れます。指定しない場合はすべての UDP を複製 します。TCP はこのモードでは複製されません。 - どの回線も配信を単独で運べること(推奨): 各回線がそれぞれ全部のコピーを送るため、 1 本ずつが配信のビットレートを余裕を持って上回るアップロード速度を必要とします。 20 Mbps の配信なら、どの回線も 20 Mbps 以上が必要です。1 本が一時的に遅く なっても、ほかの回線が配信を運べるあいだは問題ありません。どの回線も運べなく なると、mqvpn はコピーをやめて
Redundant = falseと同じように各パケットを 1 回だけ送り、運べそうな回線が出てきたら、しばらくしてコピーを再開します。 切り替えるたびにログにredundant mode: ...と出ます。それでもRedundant = falseより多くのパケットが失われることがあるので、回線が配信より 遅いことが多い場合はオフのままにしてください。 - クライアントは
CC = bbrに(推奨):CCは mqvpn が送る速さの決め方です。 セルラー回線は、無線のため混んでいなくても少しパケットが失われることが あります。デフォルトのbbr2はそのあと送る速さを落とすので、配信を丸ごと 運ぶには遅くなってしまうことがあります。bbrは速さを保ちます。 ベンチマークを取ると、冗長モードではbbrのほうがパフォーマンスが良い 結果となりました。 - アプリには重複が届く: mqvpn は余分なコピーを取り除かないため、受信側の アプリは同じパケットを複数回受け取ります。SRT など重複を捨てるプロトコル なら問題ありません。それ以外の UDP アプリで使う前に、重複を捨てるかどうか 確認してください。
- Reorderとの併用: 冗長モード対象の送信 UDP には、Reorder による 並べ替え・重複除去は適用されません。
RedundantPortsが空の場合、 上り UDP 全体が Reorder の対象外になります。冗長モード対象外の通信と ダウンロードは、通常どおり Reorder の設定・ルールに従います。 - アップロードのみ: クライアントが送るトラフィックだけが対象です。 ダウンロードは変わりません。サーバはこの設定を無視します。
- 準備中の回線や切断された回線にはコピーを送りません。ほかの回線より 遅れている回線にも、追いつくまで送りません。使える回線が 1 本だけの ときは、その回線に 1 回だけ送ります。
- 接続直後の 1 秒ほどは、回線の送信速度が上がりきるまでのあいだ、少しパケットが 失われることがあります。
Scheduler = backup_fecとは併用しても効果がありません(2 本目の回線が 待機のままのため)。
以前の Reinjection = dgram は廃止され、この冗長モードに置き換わりました。 設定ファイルに dgram が残っていると警告が出て Reinjection = off で 動作します。代わりに Redundant = true を使ってください。
パスの重み付け
WLB はトランスポートの実測値からパス重みを自動更新します。手動で重みを設定する必要はありません。
仕組み:
- ロス率・RTT・cwnd から各パスの推定スループットを算出し、パス間のトラフィック分配比率(重み)として使用します
- deficit WRR が、その重みに基づいてパケット/フローの割り当てを行います
- 既存の TCP フローピンは再利用され、アイドル・高ロス・パス障害時にはエントリを破棄します
- ラウンド境界やパス復帰イベントで重み/deficit を更新します
これにより、非対称パス(例: 300 Mbps 有線 + 80 Mbps 無線)が手動チューニングなしで効率的に活用されます。
仕組み
┌─────────────────┐ ┌─────────────────┐
│ Application │ │ Internet │
├─────────────────┤ ├─────────────────┤
│ TUN (mqvpn0) │ │ TUN (mqvpn0) │
├─────────────────┤ ├─────────────────┤
│ MASQUE │ HTTP Datagrams │ MASQUE │
│ CONNECT-IP │◄──(Context ID = 0)──────►│ CONNECT-IP │
├─────────────────┤ ├─────────────────┤
│ Multipath QUIC │◄── Path A (eth0) ──────►│ Multipath QUIC │
│ │◄── Path B (wlan0) ──────►│ │
├─────────────────┤ ├─────────────────┤
│ UDP (eth0/wlan)│ │ UDP (eth0) │
└─────────────────┘ └─────────────────┘
Client Server各パスは特定のネットワークインターフェースにバインドされた個別の UDP ソケットです。Multipath QUIC が QUIC レイヤーでパスを管理し、サーバーからは複数のパスを持つ単一の QUIC 接続として認識されます。
ベンチマーク
非対称デュアルパス環境(300 Mbps + 80 Mbps、netem によるエミュレーション)でのフェイルオーバーおよび帯域集約の計測結果は、ベンチマークレポートを参照してください。
プロトコル標準
| プロトコル | 仕様 |
|---|---|
| MASQUE CONNECT-IP | RFC 9484 |
| HTTP Datagrams | RFC 9297 |
| QUIC Datagrams | RFC 9221 |
| Multipath QUIC | draft-ietf-quic-multipath |
| HTTP/3 | RFC 9114 |