Multipath TCP (MPTCP)をAmazon EC2で試してみた #WWDC17
ども、大瀧です。
WWDC 2017では、iOS周辺のネットワーク機能を紹介するAdvances in Networkingというセッションがありました。セッションについてはこちらの記事が詳しいです。
iOSはこれまでIPv6や常時SSLなど、新しいWebネットワークテクノロジーの牽引役として様々な働きかけをしてきました。今回のセッションで取り上げられたMultipath TCP(MPTCP)は、iOS 11でiOSアプリ向けの実装予定で、これを皮切りに今後広く使われるのを期待しています。本記事では、サーバー側としてAmazon EC2でMPTCPを試してみた様子をご紹介します。
MPTCPとは
Multipath TCP(MPTCP)は、トランスポートプロトコルであるTCPでマルチパス(複数経路)通信を実現する技術です。WWDCのセッションではLTE回線とWi-Fiの2経路を用途や回線状況に合わせて使い分け、アプリとサーバー間の通信を円滑に行うユースケースが示されていました。
仕様自体はRFC6824で標準化されており、クライアントからサーバーまでのEnd to EndでMPTCPをサポートすることで実現します。
OSサポートとしてはLinux実装があり、カーネルにパッチを当てる必要があります。
Amazon EC2ではパッチ適用済みの公開AMIが便利です。
今回はこちらのAMIを利用します。
動作確認環境
- リージョン: us-west-1
- AMI: ami-60a28100(MPTCP-v0.92)
先述のWebページではap-northeast-1のAMIも紹介されていますが、正常に起動してこなかったので、なんらかの設定不備があるようです(HVMのところがPVになっているのかも)。
検証手順
今回は同じVPC内に上記AMIから起動したEC2を2台用意し、片方のインスタンスでWebサーバー(Nginx)を実行、もう片方からcURLを実行してWebサーバーにアクセスしその様子をtcpdumpでキャプチャします。マルチパスの動きを見たいので、クライアント側にPrivate IPを追加しているのがポイントです。
- クライアントIPアドレス: 172.31.5.60, 172.31.3.145(追加)
- サーバーIPアドレス: 172.31.12.74
Amazon Linux AMIでは追加したPrivate IPが自動で構成されますが、今回のAMIでは以下コマンドを実行し手動でIPエイリアスを設定します。
$ sudo ip addr add 172.31.3.145/20 dev ens3:1
では、1つの端末でtcpdumpを実行しつつ、2つ目の端末を開き、cURLコマンドでサーバーにリクエストを送出します。
$ sudo tcpdump -nn port 80 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on ens3, link-type EN10MB (Ethernet), capture size 262144 bytes
$ curl http://172.31.12.74/ (レスポンスは省略)
tcpdumpを実行している端末にキャプチャが表示されました。普段のTCP接続よりもボリュームが多いのがわかります。
15:41:33.557044 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [S], seq 2400131088, win 26883, options [mss 8961,sackOK,TS val 1110938 ecr 0,nop,wscale 7,mptcp capable csum {0xc67c4184f77fdb3}], length 0 15:41:33.557104 IP 172.31.12.74.80 > 172.31.5.60.52262: Flags [S.], seq 3704871592, ack 2400131089, win 26787, options [mss 8961,sackOK,TS val 1303431 ecr 1110938,nop,wscale 7,mptcp capable csum {0x8a5c5b6fcd7bf231}], length 0 15:41:33.557225 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [.], ack 1, win 211, options [nop,nop,TS val 1110939 ecr 1303431,mptcp capable csum {0xc67c4184f77fdb3,0x8a5c5b6fcd7bf231},mptcp dss ack 2505716611], length 0 15:41:33.557278 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [.], ack 1, win 211, options [nop,nop,TS val 1110939 ecr 1303431,mptcp add-addr id 3 172.31.3.145,mptcp dss ack 2505716611], length 0 15:41:33.557287 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [P.], seq 1:77, ack 1, win 211, options [nop,nop,TS val 1110939 ecr 1303431,mptcp dss ack 2505716611 seq 2100110096 subseq 1 len 76 csum 0x9a94], length 76: HTTP: GET / HTTP/1.1 15:41:33.557300 IP 172.31.12.74.80 > 172.31.5.60.52262: Flags [.], ack 77, win 210, options [nop,nop,TS val 1303431 ecr 1110939,mptcp dss ack 2100110172], length 0 15:41:33.557411 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [S], seq 3818148095, win 26883, options [mss 8961,sackOK,TS val 1110939 ecr 0,nop,wscale 7,mptcp join id 3 token 0xc719e5b2 nonce 0xe19a24b4], length 0 15:41:33.557427 IP 172.31.12.74.80 > 172.31.3.145.46490: Flags [S.], seq 704894328, ack 3818148096, win 26787, options [mss 8961,sackOK,TS val 1303431 ecr 1110939,nop,wscale 7,mptcp join id 2 hmac 0x588500081f312dc nonce 0xe9ba400d], length 0 15:41:33.557521 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [.], ack 1, win 421, options [nop,nop,TS val 1110939 ecr 1303431,mptcp join hmac 0x6388de4da398012ffe0effd1d42ce579c5e361a4], length 0 15:41:33.557542 IP 172.31.12.74.80 > 172.31.3.145.46490: Flags [.], ack 1, win 419, options [nop,nop,TS val 1303431 ecr 1110939,mptcp dss ack 2100110172], length 0 15:41:33.557584 IP 172.31.12.74.80 > 172.31.3.145.46490: Flags [P.], seq 1:860, ack 1, win 419, options [nop,nop,TS val 1303431 ecr 1110939,mptcp dss ack 2100110172 seq 2505716611 subseq 1 len 859 csum 0x7e75], length 859: HTTP: HTTP/1.1 200 OK 15:41:33.557680 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [.], ack 860, win 434, options [nop,nop,TS val 1110939 ecr 1303431,mptcp dss ack 2505717470], length 0 15:41:33.557920 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [F.], seq 1, ack 860, win 434, options [nop,nop,TS val 1110939 ecr 1303431,mptcp dss fin ack 2505717470 seq 2100110172 subseq 0 len 1 csum 0xe0c4], length 0 15:41:33.557957 IP 172.31.12.74.80 > 172.31.3.145.46490: Flags [F.], seq 860, ack 2, win 419, options [nop,nop,TS val 1303432 ecr 1110939,mptcp dss fin ack 2100110173 seq 2505717470 subseq 0 len 1 csum 0xa0bf], length 0 15:41:33.558047 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [F.], seq 77, ack 1, win 434, options [nop,nop,TS val 1110939 ecr 1303431,mptcp dss ack 2505717470], length 0 15:41:33.558053 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [.], ack 861, win 434, options [nop,nop,TS val 1110939 ecr 1303432,mptcp dss ack 2505717471], length 0 15:41:33.558063 IP 172.31.12.74.80 > 172.31.5.60.52262: Flags [F.], seq 1, ack 78, win 419, options [nop,nop,TS val 1303432 ecr 1110939,mptcp dss ack 2100110173], length 0 15:41:33.558081 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [.], ack 861, win 434, options [nop,nop,TS val 1110939 ecr 1303432,mptcp dss ack 2505717471], length 0 15:41:33.558093 IP 172.31.12.74.80 > 172.31.3.145.46490: Flags [R], seq 704895189, win 0, length 0 15:41:33.558148 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [.], ack 2, win 434, options [nop,nop,TS val 1110939 ecr 1303432,mptcp dss ack 2505717471], length 0
紐解いていきましょう、まずは1行目。MPTCPはTCPの拡張フレームに情報が入ります。このトラフィックだとmptcp capable csum {0xc67c4184f77fdb3}]
ですね。なお、tcpdumpがMPTCPに対応していないバージョンだとフレーム内の形式が解析できないので、この部分はunknown
と表示されます。
15:41:33.557044 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [S], seq 2400131088, win 26883, options [mss 8961,sackOK,TS val 1110938 ecr 0,nop,wscale 7,mptcp capable csum {0xc67c4184f77fdb3}], length 0
その後、3WAYハンドシェイクに乗っかる形で接続元、接続先でサポートするMPTCPの機能のネゴシエーションが行われMPTCPの動作モードが決定します。
続いて4行目。add-addr
モードでクライアントIPアドレスが追加されているのがわかります。これによって7行目以後、2本目のTCPセッションが確立されマルチパスで動作する様子がわかります。
15:41:33.557278 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [.], ack 1, win 211, options [nop,nop,TS val 1110939 ecr 1303431,mptcp add-addr id 3 172.31.3.145,mptcp dss ack 2505716611], length 0
15:41:33.557411 IP 172.31.3.145.46490 > 172.31.12.74.80: Flags [S], seq 3818148095, win 26883, options [mss 8961,sackOK,TS val 1110939 ecr 0,nop,wscale 7,mptcp join id 3 token 0xc719e5b2 nonce 0xe19a24b4], length 0
実際のHTTPリクエスト、レスポンスを見てみると、リクエストは1つ目のクライアントIPアドレス172.31.5.60
から送出されているのに対して、レスポンスが2つ目のクライアントIPアドレス172.31.3.145
に返ってきているのが面白いですね。
15:41:33.557287 IP 172.31.5.60.52262 > 172.31.12.74.80: Flags [P.], seq 1:77, ack 1, win 211, options [nop,nop,TS val 1110939 ecr 1303431,mptcp dss ack 2505716611 seq 2100110096 subseq 1 len 76 csum 0x9a94], length 76: HTTP: GET / HTTP/1.1
15:41:33.557584 IP 172.31.12.74.80 > 172.31.3.145.46490: Flags [P.], seq 1:860, ack 1, win 419, options [nop,nop,TS val 1303431 ecr 1110939,mptcp dss ack 2100110172 seq 2505716611 subseq 1 len 859 csum 0x7e75], length 859: HTTP: HTTP/1.1 200 OK
まとめ
iOS11でサポート予定のMPTCPをAmazon EC2で試す様子をご紹介しました。MPTCPはTCPの拡張として透過的に動作することかた、様々なアプリケーションプロトコルでMPTCPのメリットが享受できます。
一方で、クライアントが複数の異なるIPアドレスでサーバーにアクセスすることから、サーバーの運用としてはいろいろ注意するべき点がありそうです。Webアプリケーションであれば、同一セッション内でクライアントIPアドレスが変動する可能性があるので、ログ解析においてリモートIPをクライアントの識別子として利用するのは難しそうです。また、End to EndでのMPTCPサポートを求められますので、ISPやクラウドのネットワーク設備がMPTCPをサポートするのか、しない場合の通常のTCPにフォールバックしても問題が無いかなど運用上チェックする項目が増えるでしょう。