初めに
タイトルが全てです。ファイル転送をクライアントサーバ型とP2Pで実装して速度を比較しようとしましたが、良い結果が得られなかったのでその過程をここで供養します。
目次
クライアントサーバ型とP2Pの通信方式について
P2Pに立ちはだかる課題「NAT越え」とは
NATを越える為の技術
基本P2Pの方が早い
仮説
検証方法
結果
考察
まとめ
クライアントサーバ型とP2Pの通信方式について
クライアントサーバ型
コンピュータをサーバ(サービスを共有する側)とクライアント(サービスを授受する側)に分け、役割を分担して運用する仕組みです。
クライアントはサーバに対してほしいデータをリクエストし、それに対してサーバは要求されたデータを送ります。
P2Pと比較したときに、クライアントサーバ型は中央集権型の構造として語られます。おそらく最もオーソドックスな通信方法。
例:Amazon、楽天等のECサービス、Facebook, Twitter等のSNSサービス
長所:主となる部分の改造が楽、管理者の権限が強くサービスへの影響力が大きい
短所:サーバへの負荷が集中しがち、サーバ障害のリスクが高い
P2P
「Peer-to-Peer」の略称。クライアントがサーバを介さずに端末同士で直接データをやりとりする方式です。各端末のことを「ノード」と言ったりもし、各ノードがすべて繋がっているのをフルメッシュ接続と呼びます。クライアントサーバ型と比較したときに、P2Pは非中央集権型や自律分散型の構造として語られます。
近年だと、ブロックチェーンを基盤とした各種サービスの台頭で注目を集めてるらしい。
例:WebRTC, 暗号通貨
長所:データの分散管理、ゼロダウンタイムの実現、匿名性を確保しやすい
短所:送信元の安全性を担保し辛い、ネットワーク全体の負荷が高い
P2Pに立ちはだかる課題「NAT越え」とは
NAT(Network Address Translation)は、ネットワーク上におけるIPアドレスを変換する技術です。インターネットが全世界に普及してもグローバルIPを使い切らないようするために生まれ、プライベートIPアドレスとグローバルIPアドレスを双方向に変換するのに使われています。NAT配下のホスト同士で通信しようとする場合、NATデバイスは外部から、その配下のホストに対して直接パケットを送信する手段は存在しません。IPアドレスを枯渇させない為とはいえ不便ですね。
- P2P通信には接続相手のグローバルIPアドレスが必要
- 互いのプライベートIPアドレスやポート番号を教える手段が必要
NATを越えた通信を行うためにはこの2つを解消しなければなりません。
NATを越える為の技術
STUN: LAN内のクライアントに、WAN側から観測できるIPアドレスとポート番号を伝達するプロトコル
TURN: NAT越えを要する通信の間にTURNサーバーを挟んで、相手との通信をリレーするプロトコル。ポートを解放できないときに使われます。
基本P2Pの方が早い
高い同期性が必要な作業は、従来主流であったサーバ・クライアント方式ではリアルタイム性で必要要件を満たすことが出来ないという問題がある。これに対処する為に、現在高度なリアルタイム性が必要なシステムではエンドツーエンドを直接繋いで遅延を抑制できるP2P方式が採用される場合がある。
中川 et al.「WebRTCによる宅内環境間P2Pラウンドトリップタイム 計測」. https://tlab.hongo.wide.ad.jp/papers/kou_dicomo2021.pdf
P2Pの方が早いらしい。
疑問に思ったこと
一般的には、クライアントサーバ型とP2PではP2Pの方が、データの転送速度は早いとされている。一方で、TURNサーバを挟んだことで、クライアントサーバ型とモデルが似て速度はあまり変わらないのでは?
仮説
暗号化・複合化のオーバヘッドにより、クライアントサーバ型の方が転送速度は遅くなるのではないか
クライアントサーバ≦TURN<<越えられない壁<<STUN
暗号化・複合化の手間、ルーティングの最適化の観点からこんな感じになると予想しました
検証してみた
ネットで見つけた検証記事の構成を調べたが、見つからなかった為、自前で環境を作って検証システムも準備した
なお、時間と技術的制約の都合上TURNは扱わず、確実に差が出るであろうSTUNでの比較を優先しました(勉強会の日程がキツキツ...)
TURN編は気が向いたらやります
実行環境:
AWS EC2(Tokyo) T2.Micro x 3
3つのインスタンスをそれぞれClient A, Client B, Serverとして扱う
検証方法
クライアントサーバ:
Serverにftpsサーバー(vsftpd)を用意して、A→Server→B→Server→Aとファイル送って返します。コマンドラインでClientからServerにファイルを送る方法が無かったので、FTPクライアントを友人の協力のもと作成し、それを使いました。 https://github.com/sandy-sunday/simple-ftp
P2P:
Serverをシグナリングサーバにして、A→B→Aとファイルを送って返してもらいます。シグナリングはtsuzu さんのsigserver https://github.com/tsuzu/sigserver を、クライアントからの転送は同じくtsuzuさんのftrans を使いました https://github.com/tsuzu/ftrans
暗号化は共にSSL/TSL
検証結果
Aがファイルを送信して、Bからのファイルを受け取るまでの時間を計測しました。オーバーヘッドの影響も考慮して二つのサイズのファイルでテストしてます。
5mbの画像場合 | 185mbの動画の場合 | |
---|---|---|
クライアントサーバ | 346 ms | 10578ms |
P2P | 3309 ms | 27576ms |
考察
結果はP2Pの惨敗。暗号化と複合化の手間やルーティングの効率を考えるとP2Pが負けることはないと思いましたが、実際には3倍の速度差が出てしまいました。
ファイル転送関連はプログラムの内部ロジックによって、同じ回線でもパフォーマンスが異なることがあるので、利用したftransか利用ライブラリのgo-easyp2pが最適化できていない可能性があると感じました。(さらに掘り下げればquic-goがありますが、調べた限りでは遅いという話は見つからなかったのでひとまず置いておきます)
今の僕にはコードの速度面まで読み解くスキルは無いので、さらに原因を突き詰めるには通信確立の確立が遅いのか、ファイル転送自体が遅いのかを調べることが次のステップになりそうです。wireshark等のパケットキャプチャツールを使って検証できると思われますが、時間的制約により調査はここまでで一度ストップします。仮に、この問題の切り分けが成功したら調査するコード量をうんと減らすことができると期待してます。
まとめ
基本的に遅延を減らしたいならP2Pが有効らしい!(ネット調べ)
ただし、利用するツールによって速度は大きく変わることもあるので実装を読み解くことも必要になるということを学びました