読者です 読者をやめる 読者になる 読者になる

たごもりすメモ

コードとかその他の話とか。

ネットワークの遅延について真面目に書く

遅延(レイテンシ)とはなにか? - はてなポイント3万を使い切るまで死なない日記
この記事に果てしなくテキトーなことが書いてあってこれを真っ向から信じられると大変迷惑なので、こと細かに真面目に書くことにする。

……つもりだったが、なんか果てしなくめんどくさくなったのでテキトーに書き散らすことにした。大学の教科書にそのへん詳しいのがいくらでもあったのに、見付からねーし。どこいったんだ。

信号の伝送速度について

まず光速度 3.0*10^8 m/s というのは真空中の値*1であって、光ファイバや電線の信号伝送速度はもっと遅い。一般的には光ファイバが 2.0*10^8 m/s 程度とか言われていて、電線についてもモノによってあれこれある。詳しくは波長短縮率とかの単語でググれ。ざっくりとでも30万キロとか恥ずかしいことは言うな。

またどんな距離の都市間でも直接接続できるわけではない。500kmくらいなら今時は行けるらしいし沖縄にもIXがある時代なんてスゲーなとは思うが、それでもデータセンタによっては複数の中継地を経由しないと到達できない場合もある。エンドユーザのインターネット回線はその最たるもので、NTTのフレッツなどを使用していればISPのデータセンタを経由*2し、NTTの地域フレッツ網に接続され、さらに地方の交換局内の機器を経由してから各家庭向けの光ファイバに乗るわけだ。
で、光ファイバと導線イーサネットの変換にはメディアコンバータというものが使われ、これがまた遅延を生む。詳しくは往復遅延時間とかでググれ。イーサネットのスイッチ類やルータも当然遅延を生む。このあたりの機器は気付いたら信じられないような台数が間に挟まったりしててあんまり馬鹿にできない。

もうひとつ大事なのは、普通は遅延(レイテンシ)というものは1パケットとそのACK(受け取ったという応答)の往復にかかる所要時間 RTT (Round-Trip-Time) で見るということで、片道にかかる時間だけを見るのは普通は意味がない*3。ゲームの通信対戦をやってたら、今手元で入力したものが相手に送られ、相手側で受け取ったという信号(ACK)が送信され、それをこちら側で受け取って初めて「1フレームの処理が完結した」ということになる。RTTのことを考えずに片道の時間が1/60secで済むとか言ってたらただの馬鹿なので注意されたい。毎秒30フレーム処理できるつもりで設計したのに15フレームしか出ない!とか愚かな末路にハマることになるぞ。

データの転送時間について

データの転送時間(一定の量のデータの送信が完了するまでに必要な時間)のことは、マトモな技術者であればレイテンシなどとは絶対に呼ばない。専門的な話をしているのにそんなこと言ったらハナで笑われるので注意しよう。ハナで笑われるだけならともかく、その後いっさい話を聞いてもらえなくなる可能性すらある。

ホスト間でのスループット(単位時間あたりに転送可能なデータ量)は、TCPであればRTTが大きいほど低くなる。UDPであれば変わらない*4。これはTCPが必ずACKを要求することによる。仮に東京のホストからブラジルのホストまでの経路の全てが超広帯域(10Tbpsとか)の線で繋がっていたとしても、RTTが大きいのでTCPを用いたデータ転送でそんなに高いスループットで通信することはできない。*5

本当は回線の帯域が広いことと遅延が低いことはイコールではないのだが、まあ半分以上は正しいと考えていいだろう。なぜなら、帯域が広いと同じ大きさのデータの転送時間は短くなるからだ。100キロバイトのデータを転送する場合には実行転送速度が1Mbpsしかでていない場合は0.8秒(800ミリ秒)かかるが、10Mbpsでていると、0.08秒(80ミリ秒)で済む。したがってデータ量が大きい場合は(1)の遅延は無視できて、大部分はデータの転送時間による遅延のほうが全然大きくなる。

遅延(レイテンシ)とはなにか? - はてなポイント3万を使い切るまで死なない日記

半分どころか完全に間違ってる。
まず、「回線の帯域が広いこと」はイーサネットのピア間通信のことを通常指して、自宅のインターネット回線なら、自宅のメディアコンバータと基地局とのあいだでのリンクアップ速度のことだ(仮にフレッツ光ファミリータイプだとすると100Mbps。)。自宅のメディアコンバータと基地局の間のデータ転送時間を測りたいというなら止めはしないが、これはもちろん無意味だ。
で、実際にデータの転送を行うときの実効帯域は通信のエンドtoエンドでのもので、これは実際にデータを流してみないと分かったもんじゃない。相手のサーバがネットワークに繋がってる線は10BASE-Tで10Mbpsだったり、あるいはデータセンタで契約している専用線は2Mbpsとかのものかもしれない*6。接続帯域と実効通信速度のふたつは全く違う事柄なので絶対に混ぜて考えてはいけない。

んでデータ量が大きければ信号の伝送速度は無視できる? 馬鹿を言ってはいけない。前にも書いたがTCPというのは原理的にACKを要求するため、ひとつパケットを送ったら相手が次を受け取れるという信号(ACK)*7を送って寄越すまでは次のパケットを送れない。信号の伝送速度が遅い、つまりデータの入ったパケットを送ってからACKが返ってくるまでが遅いというのは、必然的に実効転送速度の低下を意味する。
やりとりしているデータが1パケット(4096バイトとか)に収まる程度に小さい場合は実効転送速度が低くても1回分のRTTでやりとりが完結する*8が、データが大きく複数のパケットに分割されるような場合は、複数回のやりとりを経なければならず、長い時間がかかるのは明らかだ。

ところで実効転送速度というのは、上記で説明した通りに通信のレイテンシも含めて叩き出されるので、実効転送速度が(TCPでの計測で)高いなら大抵の場合はレイテンシも短い。が、レイテンシが短いからといって実効転送速度が高いとは限らない。

なお、転送するデータ量が大きい場合にはレイテンシだけを見るのはあまり意味がなくなるというのは本当の話で、ファイルひとつのダウンロードに30秒かかるときに、転送データの最初のパケットがやってくるまでの時間*9に0.3秒かかろうが0.5秒かかろうが、大した問題ではない。
ただし繰り返すが、データ全体の送信完了までに何秒かかろうと、それはレイテンシの問題とは絶対に呼ばない。

と思ったら誤解していた

元の文を(4)まで読んではじめて分かるのだが、ここで言っている「データ転送時間」はパケット単位で、かつデータリンク層におけるピア間の通信のことらしい。

ただ、その場合の(2)でのデータ長だが、パケット単位で分割されて送られているので、最大のパケットサイズのときデータを送るのに必要なデータ転送時間で考えればいい。

遅延(レイテンシ)とはなにか? - はてなポイント3万を使い切るまで死なない日記

いや、そりゃ(2)の文章からは分かりませんて。だって100キロバイトのパケットなんか存在しないもん。いわゆるインターネットで使用されているIPv4のパケットの全長の最大は65535bytesであり、これを超えることは原理的に不可能だ*10
さらにイーサネットの制約もある。通常のイーサネットはフレームサイズ(一度に転送するデータの単位)が1500バイト程度*11であり、これを超えるサイズのデータを転送する場合には自動的に分割されて配送される。今ならジャンボフレームといってもっと大きいフレームサイズを許容するものもあるが、経路全体が対応していないと意味がないのでこれも省略。

で、肝心なのは「回線の帯域」はひとつのネットワーク(データリンク層単位)でしか決まらないってこと。つまりお隣のスイッチまでは100Mbpsかもしれないが、そこから更に隣のスイッチまでは10Mbpsで繋がってるかもしれない。ルータの向こうは1.5Mbpsかもしれない。ホスト間での通信の話をするときに「何Mbpsの回線で接続されている」なんて話にはほとんど意味がないわけだ。*12

バッファリングについて

まずネットワークレイヤで行われるバッファリング(フロー制御やデータリンク層におけるバッファリングなどなど)と、アプリケーションで行われるバッファリング(動画ストリーミング配信などでブラウザ上でロード中バーがにょきにょき伸びるアレ)は目的も実装も完全に別のもので、絶対に混ぜてはいけない。ストリーミング配信サービスを作っているときに、ブラウザ上でのバッファリングによる実時間からの遅れをネットワーク的なレイテンシと混ぜて考えるような発言をするとハナで笑われるので注意しよう。ハナで笑われるだけならともかく(以下略)。また圧縮や暗号化アルゴリズムの処理単位(バケット・bucketと言ったりする)が溜まるまで待つことも確かにバッファリングと言ったりする。あんまり聞かないけどね。めったに問題にならないから。

まずアプリケーションにおけるバッファリングだが、これは完全に途中でのパケットロストの可能性への対策として作られているもので、途中で回線の異常やら何やらにより一時的にデータが受け取れない状態になったとき、それがバッファリングの範囲内であれば「ユーザにはデータ通信が切れていないかのように見せ続ける」ためのものだ。何秒分をバッファリングしておくかは完全にアプリケーションの設計による。3秒分をバッファに積んでおけば、2秒間データの受信が途切れても、バッファしてある分が尽きる前に次のデータの受信に成功すればエンドユーザにはデータ通信が途切れたことを気付かせずにすむ*13
ただしバッファ時間を3秒とるということは、どんなにスムーズに転送できている場合でも「受け取ったデータから3秒間分は必ず後追いで再生する」ということになるため、世界のどこかで行われている配信元の出来事は、必ず3秒遅れてエンドユーザのもとで再生されることになる。コンサート映像を垂れ流すだけなら誰も気付かないかもしれないが、同時に音声通話などもしていたりすると、ほぼリアルタイムの音声に較べて映像だけ3秒遅れでやってくることになったりするため、使用感に大きな影響を与える。アプリケーション実装上の注意点でもあるし、どうチューニングするかが重要なところだ。

ネットワークレイヤでもさまざまなバッファリングが行われる。データリンク層で行われたりIP層で行われたり。ただしここでのパケットの遅延はすべて前述したRTTにかかってくるので、ここまで書いた話で全てこと足りる。各レイヤの詳細について知りたい人はググれと言いたいところだが、多分ググってもそこまで詳しい話が出てくるとは期待できなさそうな気がするので、タネンバウム先生の「コンピュータネットワーク」でも読め。俺も新しい版のが欲しい。読む時間つきで。

圧縮・暗号化において低遅延のアルゴリズムのものを用いるというのはアリだ。アリだが、そもそもどれだけの遅延が圧縮アルゴリズム上で起きているのかをまずは考える必要がある。適当な例はないもんかと軽くググったらこんなページがひっかかってきた。数値つきで大変わかりやすい内容なので、分かってない奴は読め。

パケット音声ネットワークの遅延について – テクニカルサポート – Cisco Systems

で、正直な話、この遅延が問題になるのは高密度な双方向通信をやっているときだけだ。Skypeのビデオ通話をやれば、映像だけが3秒くらい遅れてても滅多に違和感を抱かないのがわかる。問題になるのは映像配信側が激しい動きの映像を流していて、かつ、映像の遅延時間と音声の遅延時間がズレている場合だ。某ニコニコ生放送とか多そうな感じだな。そもそもズレが出るように作るのが悪いが、まあズレを出すなというのも難しいだろう。自分でやったことはないが、血を吐くだろうなという気分にはなんとなくなる。
あんまり一般的な話ではないので、これを指して「インターネットでは遅延が大変な問題なんだ!」とか言うと真っ当なエンジニアからは指さして笑われる可能性があるので、立場と問題意識を明らかにしながら話をするのをおススメする。

ところでネタ元の (3) の項目が理解不能というか支離滅裂なんだが、誰か国語の問題として読解してくれんかね。

証明は簡単で例えばバッファリング時間を1秒とろうが100ミリ秒とろうが、その1秒だか100ミリ秒のバッファに相当するデータを転送したり処理したりする時間はそれぞれ1秒ないし100ミリ秒以内でおこなわないとそもそもリアルタイム処理できない。リアルタイムに処理できている以上、バッファしている時間以内でデータは処理しているということだ。その限りにおいては実際には何ミリ秒かかろうが、ユーザからみた場合にはバッファされている時間はまったく変化しないのだ。

遅延(レイテンシ)とはなにか? - はてなポイント3万を使い切るまで死なない日記

ユーザの手元で表示されている映像が、配信元で起きていることからどのくらい遅れてるかって話じゃないの? なんでバッファが何秒分あるかって話を例示してる話が「証明は簡単で」という文章のあとに続いてんだ? まあ多分書いてる途中でなんて書こうとしたか忘れたんだろう。

ルータについて

まあ「諦めろ」ってのは正しい。ただし説明は間違い。

実際にはIP層においては複数のルータを通じて通信しているわけで、PC−ルータ間、ルータ−ルータ間、ルータPC間のそれぞれにおいて(2)と(3)の遅延を考えて、それの総和がエンドツーエンドの通信の遅延にプラスされることになる。ただ、その場合の(2)でのデータ長だが、パケット単位で分割されて送られているので、最大のパケットサイズのときデータを送るのに必要なデータ転送時間で考えればいい。

遅延(レイテンシ)とはなにか? - はてなポイント3万を使い切るまで死なない日記

全パケットがバースト転送行われてるってんならともかく、無論そんなことはTCPではありえない*14複数のネットワークおよびルータをまたいだホスト間通信においては、IPパケットの往復が完了しない限り次が送れないのだ。そしてそれは経由するネットワークすべての所要時間の累積となる。パケットが各ネットワークでどのように分割されるかはそれぞれのネットワークのフレームサイズによるので、基本的にIPパケットの送出側が見積ることはできない*15

遅延とか言う前に、何と戦うのか考えろ

ネットワーク的な意味で遅延(レイテンシ)と言った場合には point-to-point でのRTTのことを意味するというのは前にも書いた通り。
ネットワークサービスや通信を考える場合に広く遅延(なんとなく遅く感じる、程度の意味)とか言う場合は、そもそも何と戦いたいのかをはっきりさせる必要がある。それも明確にせずに遅延遅延とか言うのはただの馬鹿だ。

通常のWebアプリケーションにおけるユーザ体験の話

自分以外に詳しい人がいくらでもいるが、要するにブラウザでなんとなく表示されるまでの時間が短いかどうかって話。javascriptCSSのロード順序および非同期化、画像読み込み方法の最適化、高速に描画されるHTMLの書きかたを考えろ。静的コンテンツを高速に返すキャッシュサーバを準備しろ。時間がかかるデータはAjax化して遅延ロードしろ。あれやこれや。

で、極めて正直に言って、この分野で「ネットワークの遅延」が問題になることはほとんどない。アメリカ西海岸まで200msのRTTがかかるのは某PaaS使用者には常識だが、それでエンドユーザがなんか不快かと言うと、ほとんどそんなもん感じないって。国内の遅いサーバの方がよっぽど害悪です。

ストリーミングサービスにおけるユーザ体験の話

まあこれも専門の方がいらっしゃるでしょう。簡単に。

単方向と双方向で大きく戦略が異なる。
単方向の場合にはあらゆる意味での遅延はほとんど問題にならない。まあ視聴者側が相互にチャットで繋がってたりしたらネタバレの危機が訪れるが、ユーザ側の回線の問題もあるので完璧にやるのは不可能と言っていい。諦めましょう。あとは前述した通り映像と音声にできるだけズレがないようにするなどの工夫が大事。アプリケーション作る腕の見せどころですね。
双方向の場合はパケットロストに対するバッファリングをどの程度入れるか、映像と音声の同期を追求するか諦めるか、などなど考えることがいっぱい。頑張ってね。

純粋にデータ同期の話

世の中にはディザスタリカバリを大真面目にやらないといけない業種というのがあって*16、そういうところは大抵カネも持ってるのでまさに湯水のようにカネをつかって都市間でデータの同期をやろうとか言い出す。
具体的に言うと東京と福岡とか東京と沖縄とかでそれぞれにでっかい超高機能ストレージ(1台1億くらいするやつ)を置き、拠点間を専用線で直結して完全にデータを同期させようとかする。ストレージに繋がったデータベースからトランザクションをコミットすると、とりあえず東京のストレージに書いたあと、それが沖縄のストレージまで同期されてはじめてコミットが完了して処理が戻ったりする。
そういう場合、ネットワークのレイテンシはもう致命的で、RTTの間はトランザクションが開放されないので秒間のI/O性能に直結したりする。そんで超高級機と超高価格回線を使ったのに性能が出ない! とか言って怒り出したりする。知るか。光ファイバ中の光速は30万キロじゃねえんだよ。光ファイバの伝送以外にもあれこれ遅延が出るんだよ。往復で考えろ。

まあそういう話には苦労してつきあうSEという人種がいるので、どうでもいいか。まあそのくらい考えとこうねってこと。

で、なんだっけ

世の中のエンジニアをdisる前に、タネンバウム先生の教科書くらい読みやがれ。

「ネットワークコンピュータ」さまざまな種類の物理層の話からオーバーレイネットワークのさわりや暗号化についてのさわりあたりまで載っててじつにいい本ですよ。第4版でも既に800ページ以上あるけど。読みましょう。

*1:厳密には定義値はもっと違うけどググれ。

*2:最近ではキャリアによってはしない場合もある。フレッツ網内での通信で閉じる場合も。が、めんどくさいので無視。

*3:音声通話をする場合には大事なのは片道の遅延だが、そういう人達は今さらこんなエントリ読むことはないので無視する。

*4:正確にはパケット損失率とアプリケーション層での再送アルゴリズムに依存する。パケット損失率がゼロであればレイテンシがいくら

*5:TCPが1セッションであれば。セッションを多重化するとかの高いレイヤでの工夫の余地はいろいろあるが、話がぜんぜん違うので省略。

*6:いや、実際にそういう商用サービスの回線見たことあるんだよね。RHELのアップデートが死ぬほど遅かった……。

*7:正確には空きウィンドウがあるという記載のあるACK

*8:本当はTCPハンドシェイクとかがあるのでもう2往復余計にかかる、が、省略

*9:ここで「レイテンシだけが効いてくる」のはこの最初のパケットの到着だけで、あとは他の複合的な要因からなる実効転送速度の問題になる

*10:IPv6であればまた違うが、ここでは無視する。

*11:ヘッダまわりの細かい話がある。VLANタグがついたりすると更に厄介なので全部省略。

*12:ほとんど、と書いたのは、もちろん経路上で最も狭い帯域の速度以上では絶対に通信ができないため。いや絶対にってのはアレだなあ。最近は経路上の2点に置いた装置で圧縮と展開をかけてショボい回線でも広帯域通信します、なんて製品もあるし。

*13:ちなみにバッファ時間が3秒というのはマズい設計で、普通はもっと長くとる。TCPタイムアウトや再送は普通は1秒や3秒といった単位で制御されているため、このくらいは簡単に無通信時間ができてしまうからだ。

*14:ACKを待つ間に送信予定のペイロードをバッファしておいて次のひとつのパケットでまとめて送るというような効率化は計られるが、そもそも今の議論ってそんな4kbytes以下の極小データは相手じゃないよね?

*15:いやまあアレとかコレといった専用のプロトコルはある。企業内の高品質広域ネットワークではそういうのが大活躍しているはずだが、ここではもちろん省略

*16:銀行とか証券会社とかあれやこれや