日本-ブラジル間の WebRTC 通信を TURN サーバー同士で中継してみた

要約

  • WebRTC で使われる TURN サーバーで日本-ブラジル間を中継
  • coturn を Google Cloud Platform 上に構築
  • coturn サーバーの external-ip 設定が重要

はじめに

 インダストリー事業本部のイチノです。業務では、リモート製品 (Optimal Remote, Optimal Second Sight, ポケットドクターなど遠隔地とコミュニケーションするための製品) で使われるコア技術をまとめた Communication SDK を担当しています。 Communication SDK では、映像や音声の送受信用に WebRTC を利用しています。 WebRTC では、ピア(参加者)同士が接続できるように STUN/TURN サーバーを利用して、通信しています。

 今回は、日本-ブラジル間を TURN サーバー同士の接続について紹介します。日本から地理的に最も遠いブラジルとの通信を想定し、 WebRTC の通信を確認してみたいという興味が発端です。せっかくなので、以前から個人的に気になっていたTURN同士が通信するということも確認してみました。TURNサーバーの振り分け方法については今回の対象とせず、案だけを最後に書いています。

所感

  • 今回、試すまで、TURN サーバー同士が繋がるということについて半信半疑でしたが、繋がるのを目の当たりにして驚きました。
  • これ、ディザスタリカバリに使えるじゃんと思いました。

TURNサーバーについて

 WebRTC では、ピアが通信するためにNAT越えする必要になる場合があります。NAT 超えするために、

  1. STUNサーバーでのホールパンチを利用したP2P通信
  2. TURNサーバーでのデータ中継

のいずれかで、ピア同士を通信させます。WebRTCは、可能な限りP2P通信を行ます。P2P通信に失敗する場合、TURNサーバーにピア間の通信を中継させます*1。WebRTCの前身であるlibjingleでは、

  • 92% が STUN を使った P2P 通信
  • 8% が TURNによる通信

が利用されていました*2。TURNサーバーを使うことで、P2P通信で接続できない通信環境に対処できます。このため、 WebRTC を使ったサービス提供時に TURN サーバーは重要な役割を持ってきます。TURNサーバーの動作、TURN 同士が通信する理由については、以下の WebRTCの裏側が参考になります。

WebRTCの裏側 · GitHub

TURNサーバーの準備

 TURNサーバーを Google Cloud Platform 上に構築しました。構築したインフラを以下に示します。

Google Cloud Platform のVPC(Virtual Private Cloud) 配下へ、日本に VM 1台、ブラジルに VM 1台を配置しています。インターネットからのアクセスに対して、VPCがVMにアクセスを振り分けます。マシンタイプは、テスト環境用にいずれも最小構成のf1-micro(vCPU x 1、メモリ 0.6 GB)を利用しています。VPC 内部のネットワーク設定についてはデフォルト設定を利用しました。内部 IP アドレスについて設計意図は、ありません。 VPC に設定するファイアウォールには、TURN サーバー疎通用に上り tcp:3478 と udp:3478 を許可しています。

 利用する TURN サーバーには、 coturn を利用します。 coturnのインストール方法については、省略します。coturn を各VMへインストールします1。構築したインフラに合わせた coturn サーバーの設定を以下に示します。

# ①テスト環境なので、STUN機能を無効化。
no-stun

# ②認証を有効化。 WebRTC では必須の設定。テスト環境ですので、認証情報を turnserver コマンドの引数で渡します。
lt-cred-mech

# ③ verbose ログを表示
verbose

# ④ TURN の IP アドレス。内部 IP アドレスを設定しています。
relay-ip=10.240.0.8

# ⑤ 外部のピアに教える TURN サーバーが待ち構えるIPアドレス。
# VPC 配下で TURN サーバー同士を通信させるための重要な設定です。
# 値は、自機の内部IPを設定してください。
external-ip=10.240.0.8

# ⑥ TURN サーバーの受信ポート
listening-port=3478

# ⑦ 使用する UDP ポートの範囲指定
min-port=49152
max-port=65535

 重要な設定は、⑤の external-ip 設定です。 external-ip で指定した IP アドレスが、TURNの接続候補 (ICE Candidate) としてピアに報告されます。接続候補が相手ピアに通知され、相手ピアのTURNが接続します。なお、 external-ip には、自機の内部 IP (ローカル IP)を設定してください。例えば、日本側のVMであれば、 10.240.0.8 を、ブラジル側の VM であれば 10.240.9 を設定します。もちろん、自機に割れ当てられた外部 IP (グローバル IP)を設定できます。

 今回構築した環境で、外部 IP ではなく内部 IP を設定した理由は、次の通りです。

  • Google Cloud Platform の VPC の 1 つの特徴である高速な帯域を利用したいから *3
  • VPC の管理されたネットワークなので、 TURN サーバー間の通信に関して、外部 IP アドレスを経由するよりも、閉ざされたネットワークでの接続を実現できるから

 最後に、turnserver コマンドで起動します。オプションには、TURN サーバーの認証情報を設定しています。

$ turnserver -c turnserver.conf  --user user1:pass1 --realm=tekitouna_realm

TURN サーバー利用手順

 ピアが、別々の TURN サーバーに接続して、 WebRTC のビデオチャットできることを確認していきます。 WebRTC の接続の確認には、 AppRTC を利用します。 AppRTC を使わない方は、この章を読み飛ばしていただいて結構です。AppRTCを利用した理由は、単に WebRTC接続のプログラム実装やシグナリングサーバーの実装が面倒だったからです。

 少々本題から逸れますが、 AppRTC での TURN サーバー設定方法について触れておきます。 AppRTC には、任意の TURN サーバーを設定できます。他のパラメータについては、https://apprtc.appspot.com/params.html をご覧ください。 https://appr.tc/?ts=https://turn.example.org/some_path の様に ts パラメーターを指定すると appr.tc のサイトは、XHR(XMLHttpRequest) で、 https://turn.example.org/some_path/v1alpha/iceconfig?key=randomchars へ POST リクエストを発行します。レスポンスボディーを JSON としてパースし、パース結果を RTCPeerConnection の引数として渡します 2 。 appr.tc が期待している JSON データは、次の通りです。

{
    "iceServers": [
        {
            "urls": ["turn:203.0.113.1:3478"],
            "username": "user1",
            "credential": "pass1"
        }
    ],
    "iceTransportPolicy": "relay",
    "iceTransports": "relay"
}

RTCIceServer と同じ値を iceServers に設定できます。 urls に構築した TURN サーバーを設定します。 username と credential は、必須です。また、iceTransports には relay を設定します。 JSON を返すサーバーを、パスごとに日本かブラジルの TURN サーバーへ向ける設定を返すように設定しておいてください。あとは、AppRTC の ts パラメータに適切なパスを含んだパラメーターで開くと、日本かブラジルの TURN サーバーへ接続してくれます。以上が、 AppRTC での TURN サーバー設定方法です。

TURN サーバー通信の確認

 通信の確認に利用した環境を、以下の図に示します。図中から、 VPC や、シグナリングサーバー、 AppRTC を説明のために省いています。

NAT配下に存在するピアが、TURNサーバー(coturn) を経由して接続します。ピアはいずれも日本国内から TURN サーバーへアクセスします。計測をしないので、気にしないでください。ピア 1 は、ブラジルの TURN サーバーに接続するピアです。ピア 2 は、日本の TURN サーバーに接続するピアです。接続したときに、 chrome://webrtc-internals を開くことで、 WebRTC の通信状態を確認できます。ピア 1 とピア 2 の通信状態を確認したときのスクリーンショットです。

図中の赤枠の部分 googLocalAddress と googRemoteAddress が内部 IP 同士で接続しあっています。  体感では、 2 秒から 3 秒の遅延が発生していました。6秒ほどの遅延が発生する時もありました。両ピアが日本にいる関係で、パケットが日本-ブラジル間を往復しており、遅延についてはまずまずといったとこでしょう。

TURN サーバーの振り分け方法

TURNサーバーの振り分け方法は、DNSラウンドロビンによる振り分けや、TURN/STUNサーバー情報をWebサーバー側で振り分ける方法が考えられます。また、クラウドサービス依存になりますが、 Google Cloud Platform の Load Balancing による振り分けが考えられます。今回は、試していません。

おわりに

 ピアは2台とも日本に在りましたが、片方のピアが日本に設定したTURNサーバーを経由し、もう片方がブラジルに設置したTURNサーバーを経由した通信を確認できました。世界各地にTURNサーバー配置することで、WebRTCを使ったサービスをより安定して提供できると考えられます。

 オプティムでは、 WebRTC 限らず様々なことに興味があるエンジニアを募集しています。

www.optim.co.jp

脚注・参考文献


  1. 2台目の環境を構築するときは、最初に構築した VM のスナップショットを使って2台目のVMを起動することをお勧めします。構築時間の短縮になります。

  2. XHR を使っているので当然のごとく CORS の制限が発生します。 JSON を返すサーバーには、 appr.tc からのリクエストを許可してください。

*1:“Real time communication with WebRTC”,< https://codelabs.developers.google.com/codelabs/webrtc-web/#0 > , 2019年2月10日アクセス

*2:Ilya Grigorik 著、和田 祐一郎/株式会社プログラミングシステム社 訳(2014), 『ハイパフォーマンス ブラウザネットワーキング ネットワークアプリケーションのためのパフォーマンス最適化』, 株式会社オライリー・ジャパン.

*3:“ここまできた ! Google Cloud Platform Virtual Private Cloud 徹底解説 - YouTube”, < https://www.youtube.com/watch?v=jMQsrEQuhOU&t=427 > , 2019年2月10日アクセス