Mirrativ tech blog

株式会社ミラティブの開発者(サーバサイドエンジニア,iOSエンジニア,Androidエンジニア,機械学習エンジニア,インフラエンジニア, etc...)によるブログです

【MPTCP】ライブ配信の通信安定化に向けて MultiPath TCP を試験導入している話

こんにちは ハタ です。
今回は Mirrativ の本番サーバの一部に試験導入している
MultiPath TCP (MPTCP) について紹介させていただきたいなと思います。

MultiPath TCP といえば、iOSの Siri で利用していることなどで一時有名になりました
今回紹介するMPTCPも同じ技術を使っており、通信の安定化に向けて取り組んでいる事項の紹介になります

MPTCP の概要と各OSの実装について

f:id:octu0:20191126175452p:plain
MPTCPのイメージ

MultiPath TCP (以降 MPTCP)は、複数の経路を通じて同じホストに対して通信が行えるTCP拡張です。
従来のTCP通信では、単一の通信パスしか使えなかったものが、複数の通信パスを利用できるようになります。
例えばスマートフォンでは 4G 回線と WiFi ネットワークが用意されているため、それぞれから同一のコネクション張り、どちらか片方の経路でコネクションが切れた場合でも、もう片方の経路で通信が維持できる仕組みです。

MPTCPはクライアント側では iOS で利用可能となっていて、残念ながらAndroid での利用はできないようです(いちおう ルート化されたものであればいけそうですがAndroid 4.x なので少し古い)
また、サーバ側では 各種Linuxディストロ 用のKernelを使うことで利用可能です(BSDは FreeBSD のものがありそうです)

今回は iOS 中心に紹介させていただきます。

MultiPath TCP 導入の目的

f:id:octu0:20191125145612g:plain
WiFi <-> 4G の切り替わり

ミラティブではライブ配信の安定化向上を日頃から行っており、MPTCPの試験導入も通信の安定化を目的に検証を進めています。

これまで、「配信が行えない」ことや「配信が止まってしまう」という声を頂いており、様々な理由で配信が正常に行えない事象があることは確認しているのですが
その中の一部の状況を調査してみると、 WiFi と 4G の頻繁な切り替えが発生し配信が不安定になっているという状況などが確認できてきました。

MPTCPの特性上、複数の経路で通信が行えるようになるため、副次的な効果として

  • WiFi <-> 4G が混在する環境のにおいてMPTCPを利用することでスムーズに通信ネットワークの切り替えが行えるようになり、ネットワーク切り替え時による通信断がなくなり配信を継続できるようになるのではないか
  • 上記に伴い WiFi <-> 4G の切替時に発生する通信の切断・接続がなくなり視聴プレーヤー側のリロードがなくなるため視聴体験の向上があるのではないか

などの効果が見込めるものとして検証を進めました。

MPTCPに対応したサーバ

ミラティブでの既存の配信サーバはTCP通信でライブ映像が配信されているため、配信サーバの前段にMPTCPサーバを設置し配信された映像/音声データを中継するように実装しました。

f:id:octu0:20191126175518p:plain
MPTCP サーバの概要

MPTCP は特殊なプロトコルではなく通常の TCP 通信も利用できるため、既存のサーバを MPTCP に対応した kernel 置き換えることも可能だったのですが、下記理由で既存のサーバとは分けてMPTCPのサーバを用意しています。

  • クライアント・サーバ間の通信よりもサーバ・サーバ間の通信は安定しているので、よりユーザさんに近い前段に設置して通信をリレーする
  • 問題がおきたときの切り分けのため
  • 今後の拡張性のため

サーバのOSについては、当時比較的新しい linux kernel 4.19.55 の Ubuntu での実装が利用できたため、Ubuntu 18.04 を選択しています
通信のリレー部分は、アプリケーションレベルでリレーの実装を行いました。(アプリケーションは難しいものではないため今回は割愛します)

また、利用している MPTCP のバージョンは v0.95 または v0.94.0(kernel 4.14.24) を利用しました。

$ sudo dmesg | grep MPTCP
[    0.582045] MPTCP: Stable release v0.95

ちなみに、MPTCPが有効であれば www.multipath-tcp.orgcurl でアクセスすると下記のようなメッセージが表示され、有効であることがわかります

$ curl www.multipath-tcp.org
Yay, you are MPTCP-capable! You can now rest in peace.

逆に MPTCP が利用できない場合は下記のように表示されます

$ curl www.multipath-tcp.org
Nay, Nay, Nay, your have an old computer that does not speak MPTCP. Shame on you!

iOS での実装について

iOS の実装ですが、iOS11 から API が公開され利用できるようになりました(WWDC 2017、iOS 12からはURLSession以外でも Network Framework で利用可能となっています)
また、MPTCPの動作確認をする際は Multipath entitlements が有効である必要があります。

Network frameworkを使っているため iOS12 以降となってしまいますが、multipathの通信が行えているかの確認は下記のように動作確認することができます
(www.multipath-tcp.orgcurl の User-Agent に偽装することで、サーバ上から確認したときと同じく Yay, you are MPTCP-capable! かどうかがわかるメッセージが取得できます)

import Network

let queue = DispatchQueue.global()
let port = NWEndpoint.Port(rawValue: 80)
let parameter = NWParameters.tcp
parameter.multipathServiceType = .handover
let connection = NWConnection(host: "www.multipath-tcp.org", port: port!, using: parameter)
connection.stateUpdateHandler = { state in
  if state == .ready {
    let message = "GET / HTTP/1.1\nHost: www.multipath-tcp.org\nUser-Agent: curl/7.54.0\n\n"
    let data = message.data(using: .utf8)!
    connection.send(content: data, completion: .contentProcessed { error in
      if let error = error {
        print("\(error)")
      }
    })
  }
}
connection.receive(minimumIncompleteLength: 0, maximumLength: 1024 * 1024 * 10) { (data, _, _, error) in
  if let data = data {
    let text = String(data: data, encoding: .utf8)!
    print("message = \(text)")
  } else {
    print("\(#function), err")
  }
}
connection.start(queue: queue)

Network Framework でのTCP通信のプログラムについては今回は割愛しますが、ライブ配信の通信部分はNetwork.Frameworkに切り替えて実装しました

NWParameters.MultipathServiceType

MPTCP の挙動を設定するパラメータとして NWParameters.MultipathServiceType には、handover / interactive / aggregate / disabled の4つの挙動を設定することができるようです

disabled を除くそれぞれのモードでの挙動は、ドキュメントを確認していただきたいのですが、MPTCP を利用して複数のインタフェースで通信できるモードは aggregate だけとなっていて、開発者モードでしか使えないようになっているようです

f:id:octu0:20191126001716p:plain
設定 → デベロッパ → NETWORKINGにあるチェックを有効にしないと aggregate は使えなかった

ミラティブでは、QAを通じて 一番違和感が少なくネットワークの切り替えができた handover モードを利用しています、
環境や状況によるかと思いますが interactive モードではどうしても 4G/LTE の接続にコネクションが残りがちのようで、WiFi 復帰時の体感がより違和感の少ない handover モード を利用することにしました。

また、iOS9 から導入された WiFi アシストの挙動によっては MPTCP が無効になるパターンもあるようです、こちらも今回は細かく取り上げないのでドキュメントを参照してください

MPTCPの通信の中身

実際に MPTCP の通信が行えているかは、MPTCPサーバ上で tcpdump を使い TCP オプションフィールドで確認できます。

07:27:20.757072 IP C > S: Flags [S], seq 3481042045, win 65535,
                          options [mss 1460,nop,wscale 6,mptcp capable {0x19fc1a796a193012},nop,nop,TS val 134990811 ecr 0,sackOK,eol], length 0
07:27:20.757150 IP S > C: Flags [S.], seq 999693183, ack 3481042046, win 27760,
                          options [mss 1420,sackOK,TS val 1195317422 ecr 134990811,nop,wscale 7,mptcp capable csum {0xbec75f1aee94529}], length 0

(CはClient、SはServerになっています、また一部見やすいように改行しています)

SYN および SYN/ACK 時に mptcp capable のオプションが付いていて通信が開始されることがわかります。
MPTCPの通信は通信の中身そのものよりも、実際に通信の切り替えの挙動を見ていただくのがわかりやすいので、MPTCPを有効にした配信の録画を見ていただければなと思います。

f:id:octu0:20191126170347g:plain
配信画面の録画(アーカイブ)のため画面そのものを20倍速にしたもので一部カットしています(画質悪くすいません...)ちなみに表示しているページは こちら です

ステータスが変化した場合でも配信が止まらずに映像が届いていることがわかり、視聴しているプレーヤーでも映像の再取得がされることなく、途切れずに配信がみれました

導入結果

その後さらに色々なパターンでの配信の検証を進めたところ

  • iOS 12/iOS 13における配信中のリトライ(再接続処理)回数が0になる ことがわかりました
  • 一方で視聴体験の向上はMPTCPあり/なしに関わらず解像度を上げる必要があることがわかりました

MPTCPを使うことで通常の配信に比べて通信の安定化に寄与していることがわかったものの 視聴体験の向上については、リロード回数を指標値にしようと思っていたものの有意な差があるわけではなさそうで、体験が悪化している減少について解像度を上げる必要がありそうでした。

とはいえ、MPTCPには期待していたどおりの効果があり、評価できそうで今後の全体に展開するかの検討材料にできそうです

その他今後の展望など

MPTCP の実装は Network.Framework の登場により実装が楽になったものの、インフラ基盤での高可用性をもった構成はもう少しノウハウが必要そうです、特にLBとの相性を考えたときに こちらの記事 にあるようにひと工夫加えてあげるとより可用性を高められそうです
今回のバージョンではまだここまでは出来ていないため今後バージョンアップを重ねたいと思っています

他にも配信だけではなく、視聴側でも MPTCP を利用することで、より途切れにくく配信を見ることができるのでより良いUXを作ることができる可能性もありそうなので、調査を深めても良さそうだなと思っています

We are hiring!

MPTCP などの技術を使ってライブ配信の安定化を一緒に作ってくれるエンジニアを募集中です! 体験入社という制度もあるのでお気軽にどうぞ!

www.mirrativ.co.jp