一年ほど前に書いた「MPTCP(MultiPath TCP)と負荷分散ってどうなんだろう」関連の話。
先日、まさに「Multipath TCP behind Layer-4 loadbalancers」と言うI-Dが出てました。iOSのsiriではMPTCPを使っているようですが、Appleの方もAuthorに含まれています。
I-D中にmillions of MPTCP connectionsという表現も出てきており大規模なインフラが伺えます。
問題
図のように、L4バランサの後ろにReverse Proxyが居てTCPの終端を行っています。Reverse ProxyがMPTCPをしゃべるイメージです。L4バランサは(送信元IPや送信元ポートを見て)TCPの通信を適切Reverse Proxyに割り振ります。MPTCPでは異なるIPからTCP subflowsが来ますが、MPTCPコネクションを受けてるRevese Proxyにちゃんと割り振る必要があります。
この時、L4バランサはTCP subflowsを同一のReverse Proxyに振り分ける必要があります。L4バランサがMPTCPを考慮するようにし、MP_CAPABLEハンドシェイクを見てトークンとバックエンドサーバ(Reverse Proxy)を紐付けておく必要があります。その紐付けに基づいてSYN+MP_JOINを適切なバックエンドサーバに振り分ける事ができます。
しかし、複数のL4バランサがあると状況が異なってきます(VIPなのか、経路が違うと別のL4バランサに繋がる場合がある想定のようです)。同じMPTCP コネクションに属するTCP subflowsが別のL4バランサにルーティングされる可能性があります。そうなると、トークンとバックエンドサーバ(Reverse Proxy)の紐付け情報を共有する必要が出てきます。他の全てのL4バランサと情報を供するのは非常に実装が複雑ですし、レイテンシを引き起こします。
もう一つの問題として多くのサーバがあると、違うMPTCPコネクションで同一のトークンが生成される可能性があります。数百万ものMPTCPコネクションを扱っていると、その確率は高くなります。トークンが衝突するとSYN+MP_JOINを適切なReverse Proxyに振り分けることができなくなってしまいます。
提案
基本的なアイディアは、L4バランサがトークンからバックエンドサーバを推測できるようにするというものである。
- バックエンドサーバ毎にある整数のレンジを決める
- L4バランサとYと言う秘密値を共有する。
バックエンドサーバは自身に割り当てられた整数レンジからXを一つ選び、Yで暗号化しトークンとする。これで、L4バランサはトークンよりバックエンドサーバを推測することが出来る。さらに、各バックエンドサーバでトークンが衝突することもなくなる。
このアプローチを用いて、問題を解決する別々の手法を2つ提案する。MP_CAPABLEハンドシェーク中に相手にトークンを伝達する方法が異なります。
Explicitly announcing the token
一つは単純に、MP_CAPABLEハンドシェイク中に平文で通知する方法です。しかし、これを可能とするためにはMP_CAPABLEハンドシェイクのワイヤフォーマットを変更する必要があります。トークンを付加するために、MP_CAPABLEを4バイト増やします。
mptcp-syncookiesがデプロイされていれば、TCPオプションの40byte中36byteが使用されます。この残りの4byteを使用してSYNセグメント中でトークンを通知します。
SYN + MP_CAPABLE_SYN (Token_A) -------------------------------------> (the client announces the 4-byte locally unique token to the server in the SYN-segment). SYN/ACK + MP_CAPABLE_SYNACK (Token_B, Key_B) <------------------------------------- (the server replies with a SYN/ACK announcing as well a 4-byte locally unique token and a 4-byte key) ACK + MP_CAPABLE_ACK (Key_A, Key_B) --------------------------------------> (third ack, the client replies with a 12-byte Key_A and echoes the 4-byte Key_B as well).