ハイパフォーマンス ブラウザネットワーキング

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

前々から気になっていた、オライリーのパフォーマンス系書籍第3弾を読んでみました。

オライリーのパフォーマンス系の第1弾,第2弾の著者であるSteve Souders(GoogleのHead Performance Engineer)がネットワークの神と言うIlya Grigorika(GoogleのDeveloper Advocate)の著書ということで、読む前からテンション上がっていました。

感想としては今ままで知らなかったワードが多く、内容も難しかったです。

個人的に覚えておきたいと感じた内容をまとめてみます。

輻輳崩壊について

パケットの往復時間がいずれかのホストの最大再送信間隔を超える場合、
そのホストは同じデータグラムのいくつものコピーをネット上に流し始める。
このときネットワークは深刻な事態に陥る。

スイッチングノードにあるすべての利用可能なバッファは最終的に埋め尽くされてしまい、
パケットを破棄する必要がある。

パケットの往復にかかる時間が最大値に達しており、
ホストは各々のパケットを何度も送信し、
最終的には各パケットのコピーが目的地に複数到着する。

これが輻輳崩壊である。
-John Nagle

過去にこういう事態が発生したためにサーバーはデフォルトの状態では輻輳崩壊を防ぐ設定になっていて、
パフォーマンス上はマイナスの設定になっていることが多いのですね。

フロー制御

受信者が処理できないほどの大量のデータを送信側から送出することを防止するメカニズムです。
TCP接続において、受信データの維持に使用可能なバッファサイズを知らせるために、
各ホストは受信ウィンドウサイズ(rwnd)をアドバタイズします。
ACKパケットが両者の最新のrwndを伝えます。

SYN,SYN ACK, ACKぐらいしか知りませんでしたが、ACKではrwndをアドバタイズしているようです。
これで輻輳崩壊は起きなさそうですが、これだけでは不十分なようです。

rwndスケーリング設定の確認と有効化

$ sysctl net.ipv4.tcp_window_scaling
$ sysctl -w net.ipv4.tcp_window_scaling=1

もし、rwndスケーリングが無効の場合、許容される未応答のデータの最大量が小さいため、
データ送信を延期して、もう一方がいくつかのパケットにACKを返すまで待つことになる可能性が高くなります。

輻輳ウィンドウサイズ(cwnd)とは

データ送信側がクライアントからACKを受け取る前に続けて送信できるデータ量。
cwndはホスト間でアドバタイズされることも交換されることもありません。

サーバーはTCP接続ごとにcwnd変数をinitcwndで初期化します。

新規TCP接続における送信中の最大量はrwndとcwndの小さい方です。

スロースタートアルゴリズムはACKを受信するごとにサーバーがcwndを1セグメント増加させてよいと
指示します。

cwndはネットワーク自体の許容量を制御するためにできたもので、  
徐々にcwndを増加させていくことでクライアントとサーバーは利用可能な帯域幅に収束させていきます

先ほどのrwndではデータ受信側の許容量を制御していましたが、 今回は帯域幅の許容量を制御するようです。

帯域幅が大きく減少し、大量のデータが転送されていると、
データは中間ゲートウェイにバッファリングされ、パケットは破棄される事態が発生します。

なお、初期cwndは10セグメントまで増加させることが推奨されているようです。

スロースタートリスタート(SSR)設定の確認・無効化

$ sysctl net.ipv4.tcp_slow_start_after_idle
$ sysctl -w net.ipv4.tcp_slow_start_after_idle=0

これで再度initcwndからACKごとに1セグメント増加させなくなります。

スロースタートは巨大なファイルやストリーミングで問題がありそうですが、
実際は小さなデータ送信の際のパフォーマンスに悪影響があるようです。

ストリーミングなどでは数百ミリ秒後に最大ウィンドウサイズで最高速度に近い速度で送信されるからだそうです。

TCP接続スループットの記録がのこぎり状

輻輳制御と輻輳回避アルゴリズムが輻輳ウィンドウサイズを調節することでパケットロスを回避しようとしているのです。

なるほど、MAX使うようにしていって、パケットロスが発生しそうになったらウィンドウサイズを小さくしているのですね。

Proportional Rate Reduction for TCP

TCPは当初最小分散制御アルゴリズムを用いていました。
しかし、あまりに保守的すぎるためPRRが開発されました。
Linux3.2以上におけるデフォルトの輻輳回避アルゴリズムです。
これがあなたのサーバーをアップグレードするもうひとつの理由です。

これはCnetOS7(Linux3.10)使うしかないですね。
initcwndも最新のカーネルの方が大きく設定できるようですし。

HOL(Head of Line)ブロッキング

TCPでは順序通りの配信の保証により、
失われたパケットが存在する場合、それ以降のシーケンス番号を持つパケットは
再送信され受信側に届くまで、受信側のバッファに保持されなければなりません。
アプリケーションがソケットからデータを読み取ろうとする際には伝送遅延と認識します。

個人的にはUDPの方が好きです。
TCPは真面目すぎる印象です。

ジッタ

ジッタは、主に信号の読取装置のわずかな不安定さや、
あるいは信号の伝送経路の影響などによって発生する。
ジッタが発生すると、信号が隣接する信号と干渉するなどして、
ノイズや音とび、音質・画質の劣化などの原因になりやすい。

これはTCPの順序通りの配信の保証に起因していたのですね。


データグラムとパケットの違い

データグラムはノード間のルーティングを行うための十分な情報を持っているもの。
パケットの中でも信頼性の低いサービスによって配信されるものを示します。
配信される保証も失敗の通知もありません。
UDPパケットはより正確にはデータグラムです。

パケットはデータブロック全般のことを示します。

WebRTCはデータグラムですね。

IPv4のアドレス枯渇問題とNAT(Network Address Translator)デバイス

ネットワークの末端にNATデバイスを配置し、
グローバルIPとポート番号の組をローカルIPとポートの組にマッピングするテーブル変換テーブルを
利用することでNATデバイスの先にあるローカルIPアドレス空間は異なるネットワークで再利用できる。

なるほどこれで、NATデバイスの数だけグローバルIPアドレスがあれば良くなりますね。 プロキシやルータ、セキュリティアプライアンスファイアウォールや他の数多くのハードやソフトの 構成部品となっているようです。 暫定処置は永久処置だと。

NATは接続状態に依存するが、UDPには状態がない

送信元ホストのIPアドレスとポートを知り返信経路を指定するには、
自身では状態を持たないUDPの状態をNATが保持する必要があります。

さらに面倒なことにNATは変換レコードをどのタイミングで削除するかを決定しなければなりません。

UDPには接続シーケンスがないため、どちらのピアも予告なしに送信を中止する可能性があります。
したがって、UDPのルーティングレコードはタイマーによって失効します。
タイマーの長さはNATデバイスのベンダ、製品、バージョンや設定に依存します。

長時間続くセッションのためのベスト・プラクティスの1つは経路上のNAT装置の変換レコード削除タイマーを
定期的にリセットするために双方向のキープアライブパケットを導入することです。

NAT装置の多くはTCPとUDPで同じタイムアウトロジックを用います。
そのため、場合によってはTCPでも双方向のキープアライブパケットが要求されます。
TCP接続が切れる場合は中間のNATのタイムアウトが原因かもしれません。

UDPだとNATデバイスの負荷が上がるようです。 WebRTCが広く普及するとNATデバイスの故障が多発しそうな気がします。

マッピングされていないため破棄されるインバウンド(外部のネットワークから内部へ)パケット

NATトラバーサル問題。
グローバル⇔ローカルのNATテーブルのエントリが存在しないため、データグラムが破棄される。
ポートフォワーディングなどのメカニズムがユーザーによって設定されていない場合、
NAT装置は単純なパケットフィルタになります。

これがSTUN,TURN,ICEの必要性につながってきます。

インバウンドのポートフォワーディング?

ポートフォワーディングはVagrantの設定であるように、
ローカルホストの特定のポートへのアクセスをゲストOSの特定のポートへのフォワーディングなどです。

逆にグローバルからローカルへのインバウンドのポートフォワーディングの設定はどのようにするのでしょうか。。

おそらくNATデバイスに設定するのではないでしょうか。

STUN(Session Traversal Utilities for NAT)

自身のネットワーク上のNATデバイスの存在を発見し、NATが存在する場合は現在割り当てられているパブリックIPとポート番号の組(自身のパブリックIPとポート番号)を取得するためのプロトコルです。

クライアントアプリケーションはSTUNサーバーにバインディングリクエストを送信して、
STUNサーバーはレスポンスとしてそのクライアントの
パブリックネットワークから見たIPアドレスとポート番号を返します。

これによって、インバウンドパケットがクライアントアプリケーションに到達できるルーティングエントリを作成する。

企業のファイアウォールによってUDPが完全にブロックされることがあります。
STUNが機能しない場合はTURNをフォールバックとして利用できます。
TURNはUDPで動作して、動作しない場合はTCPに切り替えます。

WebRTCアプリでSTUNとTURNがよく出てきますが、このためだったようです。
しかし、WebRTCはTCPで動作するのでしょうか。
おそらく動作しそうですが、遅くなりそうです。

TURN(Traversal Using Relays around NAT)

双方のクライアントが同一のTURNサーバーに割り当て要求を送信し、
続けてパーミッションのネゴシエーションを行うことで接続を開始します。

一度交渉が完了すると、双方のピアはデータをTURNサーバーに送信することで通信を行います。
TURNサーバーがもう一方のピアにそのデータを送信します。

最も信頼性が高い方法ですが、サーバー運用コスト・容量のため最終手段にすべき。

UDP通信の仲介者のような感じです。
高コストだが、信頼性は高いと。
将来的には低コストで信頼性が高い通信方法ができそうです。

ICE(Interactive Connectivity Establishment)

ICEは参加者の間の最も効率的な経路を確立するためのプロトコルです。
直接接続→STUN→TURN

通信の確立には高度な知識が必要なためにICEだけを使えば通信の確立ができるようです。

UDPの最適化

1.様々なインターネットの経路状況に耐えられなければばらない
2.送信速度をコントールすべき
3.輻輳制御を行うべき
4.TCPに似た帯域幅を用いるべき
5.パケットロス後に再送信の頻度を落とすべき
6.経路のMTUを超えるデータグラムを送信すべきではない
7.データグラムロスの処理や複製、並べ替えの処理を行うべきである
8.2分までの配信遅延に耐えられるべき
9.チェックサムを有効にすべき
10.キープアライブを用いてもよい(最低15秒間隔)

1はICEで担保してもらいます。

2,3,5,6はUDPの特性を考えると輻輳崩壊を防ぐために必要だと考えられます。

4はTURNがUDPが使えないと判断した場合にTCPを使用するからです。

7はロスすることが多いため、それを想定した作りにしろということでしょうか。
おそらく、ブラウザが実装するのではと考えてはいますが、
もしかしたら、パケットロスが発生した場合のコールバック関数が必要になるかもしれません。

8は配信遅延が短いと次々にデータグラムを送信してしまい、輻輳崩壊のリスクが高くなるからでしょうか。

9は送信した内容が変わっている場合は無効にしたいからだと考えます。

10は通常のWebアプリと同様ですね。

WebRTCなら上記条件を実装してくれているようです。
いやぁー、ありがたいですね。


TLS(Transport Layer Security)

通信を傍受する第三者は通信のエンドポイント、暗号化の種類、
そして、データの送信頻度とおおよそのサイズを推測できるが、
データを読むことや変更することはできない。

実質的にTLS1.0はSSL3.0のアップグレードです。

TLS1.0とSSL3.0は相互運用が不可能。

TLSはTCP上で動作するように設計されています。

暗号化の種類が分かるということは非常に危険なことです。 実際WireSharkで暗号化の種類が分かります。 SSL2.0は重大なセキュリティの欠陥がありますので、 いくらHTTPSでトンネリング化されていても世界中に公開されていることになります。

まだ、エンジニアの中にはSSLというワードを使う人が多いですが、 そのようなエンジニアはセキュリティに関してはあまり関心がないと言えます。

WebRTCの場合はUDPを使用しますので、DTLS(Datagram Transport Layer Security)です。 しかし、WebRTCでTURNサーバーを使用している場合はTCPを使うことがあります。 その場合はブラウザがよしなにDTLSとTLSを切り替えてくれるのでしょうか。

データを交換し始めるための3往復

1往復目
  SYN,SYN ACK, ACK

2往復目
  クライアント→サーバー
    TLSプロトコルのバージョン
    暗号スイーツのリスト
    他のTLSオプション
  サーバー→クライアント
    使用するプロトコルバージョン
    使用する暗号スイーツ
    自身の証明書
    他のTLSオプション値

3往復目
  クライアント→サーバー
    鍵交換パラメーター(RSA or Diffie-Hellman)
    MAC(Message Authentication Code)値
  サーバー→クライアント
    Finishedメッセージ
    MAC値

※MAC値は両者でネゴシエート

これはTCPハンドシェイクより大きなレイテンシになります。 TLS Session Resumptionを使用すれば1往復削減できます。 しかし、サーバーがアップグレードして 使用するTLSプロトコルバージョンや暗号スイーツが変更された場合は自動的に再度2往復行うかどうか。

RSAの重大な脆弱性

RSA
  クライアント→サーバー
    セッションの共通鍵をサーバーの公開鍵で暗号化したもの
  サーバー→クライアント
    秘密鍵を使用して、鍵を復号
    ※これ以降はネゴシエートされた共通鍵を使用してセッションを暗号化できる

常に同じ公開鍵/秘密鍵が使用される。
そのためサーバーの秘密鍵を取得すれば攻撃者はセッションを復号できます。
盗聴したセッションを暗号化されたまま保存しておいて、秘密鍵が取得でき次第復号できます。

要するにRSA秘密鍵が漏洩した場合に前方秘匿性がないという脆弱性があります。

Diffie-Hellman鍵交換

確立された短命な共通鍵はクライアント・サーバー間で送信することはありません。
新規セッションの際に動的にネゴシエートされます。

攻撃者がサーバーの秘密鍵を取得しても、現在のセッションを傍受することはできず、
過去のセッションを復号することもできません。

どういうアルゴリズムで鍵が交換されているのか気になります。 恐らく、100種類くらいの中からランダムで1つを選ぶような感じになっているのではと考えています。 共通鍵は送出されないということはランダムなのもシンクロするようになっているのでは。

ファイアーウォールとトラフィック

ファイアウォールなどの中間装置は多くの場合、80番と443番ポートのトラフィックのみ許可します。

AWSの場合は使用したいものを空けますが、80,443以外を許可した場合は 中間装置等も許可されるか試してみようと思います。

ALPN(Application Layer Protocol Negotiation)

HTTPSセッションは必要なネゴシエーションを行うために
HTTPアップグレードのメカニズムを利用できますが、
これにはパケット1往復分のレイテンシが発生します。

アプリケーションプロトコルネゴシエーションのサポートをTLSハンドシェイクに導入するTLS拡張です。
これによりアップグレードに必要な1往復を削減できます。

HTTP2.0はHTTPSが必須であり、それはHTTPSがALPNを行ってHTTP2.0対応の確認をするのですが、 ALPNではアップグレードのネゴシエーションTLSハンドシェイクに混ぜ込めるのですね。

SNI(Server Name Indication)

それぞれがTLS証明書を持つ複数の独立したサイトを単一のIPアドレスでホストしたい場合は機能しません。

このような場合に対処するためにSNI拡張がTLSプロトコルに導入されました。
クライアント
  接続するホスト名を提示
WEBサーバー
  ホスト名の検証とそれぞれのホストの証明書を選ぶ

中間装置をうまく使うか、HOSTヘッダーを使えばできそうな気もするのですが。。。
私の知識不足のようです。

TLS Session Resumption

  • セッションID
ClientHelloにセッションIDを含めて、
以前のハンドシェイクでネゴシエートされた
暗号スイートと鍵の再利用できることを知らせる。

これによって共通鍵をネゴシエートするために必要な公開鍵暗号の処理を不要にする。

こちらはTLS接続ごとにセッションキャッシュが必要になるために推奨はされていないようです。 サーバー側にキャッシュが必要だということが欠点だと考えます。 サーバーへのキャッシュはDoSに対する脆弱性の可能性があります。

  • セッションチケット
TLSハンドシェイクの最後に全セッションデータをサーバーの秘密鍵で暗号化し、
NewSessionTicketとしてクライアントに送信します。
その後クライアントはClientHelloにセッションチケットを含める。

負荷分散されたサーバーの場合、全サーバーは同一の秘密鍵で初期化されなければなりません。
そして、共有された鍵を全てのサーバー間で定期的にローテーションするためのメカニズムが必要です。

ロードバランサの設定によっては同一のIPからは同一のEC2インスタンスに割り当てるようにすれば
別でも良さそうですが、全て同じ方がいいのでしょうか。
秘密鍵が別の方が秘密鍵が漏洩した場合のリスクが少ないと思います。
前方秘匿性があればあんまり差はないですね。

共有された鍵をローテーションするまでに他のEC2インスタンスにセッションチケットが渡されたら、
再度TLSハンドシェイクしそうなような。

同じIPなのに異なるセッションチケットを渡さないようにするには やはり、ネゴシエートされた共通鍵を全サーバーで共有しないと難しそうです。 NewSessionTicket発行前に負荷分散された他のEC2インスタンスに共有すればいいのではと思いました。

信頼チェーンと認証局

Cは自身の公開鍵をBの秘密鍵で署名する。
AはBの公開鍵でCのメッセージがBの秘密鍵で署名されたことを確認する。

実際はどのようになっているのでしょうか。
Googleでは以下のようになっています。

Equifax Secure Certificate Authority
GeoTrust Global CA
Google Internet Authority G2
*.google.com

ブラウザのルート認証局のリストにEquifax Secure Certificate Authorityが入っているようです。

OCSP(Online Certificate Status Protocol)

OCSPは証明書チェーン検証の際に証明書DBデータベースに問い合わせる。

CRL(Certificate Revocation List)の場合はブラウザにキャッシュされているものが最新ではない可能性があります。
DBアクセスがキャッシュされている場合はOCSPの方がレイテンシが小さくなると思いますが、
DBアクセスがキャッシュされていない場合は失効リストがあまり長くなければ、CRLの方がレイテンシが小さそうです。

証明書の状態が失効した場合はDBからブロードキャストするようになっているのでは。

TCPの最適化とTLSの最適化

TCPの最適化をしている場合はTLSでの配信に関してアプリケーションの調整は全くない、
もしくは存在してもわずか。

TCPの最適化をしていれば、TLSのレコードサイズが大きくてTCPで再構成される可能性が低いからだと思います。 正確にはTCPにおける再構成数を計測すれば、サーバーの設定が良いかどうかが分かります。

TLSがリソースをどれくらい消費するか

CPU使用率は1%未満であり、ECDHE暗号スイーツの有効化と優先使用はCPU利用量にほとんど影響しません。

これは以外でした。
そういえば、最近HTTPSの方がHTTPより早いとのDeNAのエンジニアの記事もありましたし。

オリジンフェッチ

ユーザーごとにカスタマイズされるデータやプライベートデータを含むためエッジサーバーではキャッシュできないデータを
CDNから取得することをオリジンフェッチと言います。

クライアントは近くのCDNノードと接続して、そのリクエストをオリジンサーバーに近いCDNノードに転送して、
オリジンサーバーにリクエストが到達します。
※CDNではWarm Connection Poolを使用してオリジンサーバーへ転送する。

AWSならCloud Frontを使えばよいです。
しかし、Gunosyはだいたい日本にユーザーがいると思うのですが、
そのような場合にCloud Frontによるレイテンシの削減がどれくらいなのかが気になります。

TLSレコードサイズ

・IPv4のフレームオーバーヘッドとして20バイト、IPv6なら40バイト
・TCPのフレームオーバーヘッドとして20バイト
・TCPオプションに40バイトのオーバーヘッドを設定する

これでTLSレコードが複数TCPパケットへ分割される可能性が低くなります。 コンパイル時の設定オプションについては後ほど。

TLS圧縮

セッションハイジャック、2重圧縮のリスクがあるため無効にすべき。

デフォルトでは無効になっているかは後ほど。

HSTS(HTTP Strict Transport Security)

・オリジンへのリクエストはHTTPS
・証明書エラーをユーザーに通知

このサイトは危険です。でproceed to this siteを選択して、初めて遷移できるのはこの設定のためだったのですね。

TLSのパフォーマンス

1.TCPの最適化
2.TLSライブラリの最新化
3.セッションキャッシュとステートレス再開を有効にする
4.セッションキャッシュのヒットレートを監視して、適宜設定する
5.TLS False Startを有効にするために前方秘匿性対応の暗号化方式を設定する
6.CDNの使用
7.TLSレコードサイズがTCPの1セグメントに収まるようにする
8.証明書チェーンがTCPの初期輻輳ウィンドウを超えないようにする
9.証明書チェーンから不要な証明書を取り除く
10.サーバーにOCSP Staplingを設定する
11.TLS圧縮の無効化
12.サーバーにSNIサポートを設定する
13.HTTP Strict Transport Securityヘッダーを設定する

検査方法

$ openssl s_client -state -CAfile startssl.ca.crt -connect ドメイン:ポート

ワイヤレスネットワークの種類

PAN(Personal Area Network) → Bluetooth,NFC
LAN(Local Area Network) → WiFi
MAN(Metropolitan Area Network) → WiMAX
WAN(World Area Network) → LTE

MANが都市をカバーし、無線ネットワーク間のコネクティビティで
WANがワールドワイドをカバーし、ワイヤレスネットワークアクセスとは知らなかったです。

WiFiが有線ネットワークの無線拡張として機能するイメージは直感的ですが、
LTEがワイヤレスでワールドワイドというのは少しイメージしにくいです。

ワイヤレスネットワークのパフォーマンスの気まぐれさ

送信者の位置が数センチずれただけでスループットが倍増したりすることがあります。
そしてその瞬間に他のデバイスが近くで通信を開始して無線チャネルの競合が発生し、  
スループットが半減してしまうこともあります。
ワイヤレスネットワークは非常に気まぐれなのです。

カフェ内の音を電波に例えるとWiFiネットワークは理解しやすいですね。
* チャネル容量は空間の空気の量 * 周波数帯域幅は聞き取れる音波の幅 * シグナルの強さは声の大きさ * ノイズは他の人が発する音 * 遠近問題は大きな声を出す人がいるため声の小さい人の言っていることが聞こえなくなること * セルブリージングは周りの人の発する音によって音波が到達する距離が変動すること 電波が悪い人がスマホを振る人がいますが、セルブリージング対応していることになります。

inSSlDer

有料か。。。

WiFiは誰でも簡単にどこでも設置できます

確かに現在Set up WiFi spotとしていますし。
スマホLTEを元にWiFiスポットを作成しています。 野良WiFIには注意が必要ですね。

WiFIの動作モデル

送信中に衝突を検知できません。
送信者はチャネルがアイドル状態であることを検知したときのみメッセージ全体を
一度に送信することで衝突回避を試みます。

WiFiフレームが送信されると、送信者は次の送信を行う前に受信者からの明示的な受信確認を待ちます。

帯域幅の取り合い

2つか3つのWiFiネットワークが互いに近くに存在する場合、
周波数帯は実質的に重複しています。
つまり、同じ周波数帯域を争っているということです。

同じWIFiチャネルを使用する近隣のネットワークででHD動画のストリーミングが開始されると、
自分が利用できる帯域幅は半分以下になってしまいます。

802.11n802.11acの場合はまだ干渉の少ない5GHz帯を使用するようですので、 デバイスは最新であればあるほどいいですね。
802.11acの場合は802.11n(2.54GHz帯使用の場合)の12倍のスループットとは。

WiFiのパケットロスとTCPのパケットロス

WiFiプロトコルのデータリンク層と物理層はそれぞれ独自の再送とエラー訂正のメカニズムを持っています。
そして、これらのメカニズムはネットワーク上位層から衝突を隠蔽します。

有線と比べてもパケットロスはあまり変わらずにパケットの到達時間の変動が大きくなるようです。
つまり、ネットワーク上位層でのパケットロスが多いことを
WiFiが混んでいるからという人はネットワークのことを理解していないということになります。

Adptive Bitrate Streaming

動画の場合はリソースはエンコードされ、
5〜10秒ごとに分割され、保存されています。

クライアントがデータをストリーミングしている間、
クライアントもしくはサーバが各セグメントのダウンロード速度を監視して、
セグメントが切り替わるごとに最適なビットレートに切り替えます。

Netflixは異なる画面サイズと帯域幅に対応するため、
すべてのストリームを120のバージョンにエンコードします。
スムーズなオンデマンド動画ストリーミングの配信は簡単ではありません。

なるほど、同じ野菜をたくさん用意して、いろんなぶつ切りをしている感じですね。


WiFiの電力使用量の最適化

アクセスポイントは任意に設定可能なインターバルでDTIM(Delivery Traffic Indication Message)  
というビーコンをブロードキャストします。  
DTIMは特定のクライアント向けのデータがその直後に送信される予定であることを通知します。  
クライアントはDTIMフレームだけを受信することで  
無線をアクティブにする必要があるかどうかを判断します。  
アクティブにする必要がなければ次のDTIMフレームを受信するまで休眠状態に入ります。

なるほど、自身にデータが送信されるときのみアクティブにするのですね。

RRC(Radio Resource Controller)

RRCは誰がいつデータを送信するか、どの帯域を割り当て、どの程度の強度の信号を利用するかなど、  
各デバイスの電源状況や、その他すべての状態変数の管理とスケジューリングを行います。  

ワイヤレスチャネル上でデータを送信したい場合は、  
最初にRRCに問い合わせて電波リソースを割り当ててもらいます。  
データを受信する際には、データが到着するタイミングをRRCが通知してくれます。

そういう仕組でしたか。
WiFiの仕組みはピンときていたのですが、
LTEがWANというのがいまいちピンと来ていなかったのですが、
WAN〜無線基地局〜RRC〜スマホという感じでしたか。

WiFi or LTE

大容量のデータを転送する場合は、信号強度が良好であればWiFiの方がはるかに効率的です。  
しかし、デバイスがほとんどアイドルの場合は3G/4Gがより効率的です。  
パフォーマンスの最適化にはこれらを上手に動的に切り替えるのが理想的です。

なるほど、私には将来的にWiFiのみになる想定ができました。
WiFiの方が仕組みが単純であり、デバイスが増加すればするほどRRCに負荷がかかります。
しかし、WiFiネットワークの競合はどちらかというと薄れていくと思います。
データが年々爆増していること、802.11acなどの普及や職場と住居が近づくからです。

WiFiはデバイスが好きなタイミングで送信、
LTEはRRCが管理して、割り当て後に送信。
LTEアーキテクチャのコストとWiFiのコストを考えれば先は見えています。
既存の有線を使用して、いかに安くネットワークを構築するか。

LTE RRCステートマシーン

各LTEデバイスの電波状態は基地局によって制御されています。
高出力状態
↓
Short DRX(Discontinuous Reception)
↓
Long DRX
※DRXはネットワークコンテキストは確立しているが、リソース(電波)は割り当てられていない
※DRXはネットワークからのブロードキャストだけを待機します

送受信バイト数の0.2%がバッテリー消費量の46%を占める話は確かにと思いました。
60秒おきにビーコンを送信するアプリなどは最悪です。
そんなアプリを開発する会社に委託してはなりません。
ネットワークのことを一切理解していない、
無能なエンジニアがたくさんいることでしょう。

高出力状態からDRX状態になって、すぐに高出力状態に戻していることを理解しているのでしょうか
そういうことを考えながらソースを書いて欲しいものです。

URLを入力して、開くをタップした時

近隣の基地局と無線コンテキストを確立します(数往復)
↓
基地局にデータパケットを送信
↓
S-GW(Serving GateWay:基地局と接続し、データをRANに転送する)
↓
P-GW(Packet GateWay:デバイスのIP割り当て、外部接続の終端)
↓
外部ネットワーク

移動中の場合は基地局のハンドオーバーが発生しても、よしなにしないといけません。
また、トラッキングエリア外にハンドオーバーした場合はP-GWと連携している
MME(Mobile Management Entity:ユーザーの位置、課金)も更新しないといけません。

やはりモバイルネットワークより、WiFiですね。
LTEアーキテクチャが単純になったと言っても、
WiFiとは比べものにならないくらい複雑です。。