作者: ザンスおじさん
例
前後で同じドメイン名でインターフェイスをリクエストし、Charles 経由でパケットをキャプチャすると、以下の時間が表示されます。
- 2 番目のリクエストでは、DNS、接続、および TLS ハンドシェイクの部分はすべて であり
-
、この部分に時間のかかる部分がないことを示しています。最初のリクエストの 3 つの部分と比較すると、1 + 35 + 97
=が節約されます133ms
。 - もちろん、最初のリクエストのリクエストとレスポンスのサイズは 2 番目のリクエストよりもわずかに大きく、速度は低くなりますが、これらの違いを無視して、他の条件が同じであれば、2 番目のリクエストの方が高速になる可能性があります。最初のリクエスト。133ミリ秒。
初め
2回目
http(s)の接続多重化です。
接続の多重化
その前に、ネットワーク リクエストの開始 -> レスポンスの受信の大まかなプロセスを簡単に確認してみましょう。
- クライアントがネットワークリクエストを開始します
- DNS サービスを通じてドメイン名を解決し、IP アドレスを取得します (通常は UDP プロトコル)
- TCP 接続を確立します (3 ウェイ ハンドシェイク)。
- TLS接続(HTTPS)を確立します。
- ネットワークリクエストの送信 リクエスト
- サーバーがリクエストを受信したら、ロジックを実行してレスポンスを返します。
- TCP 接続を閉じます (4 回のウェーブ)
接続の多重化により、上記の手順 2、3、および 4 を繰り返す必要はありません。この期間を定義するには RTT を使用します。RTT (ラウンドトリップ時間、ラウンドトリップ時間) は、ネットワーク要求が発信元から宛先に送信され、その後発信元に戻るまでにかかる時間の長さです。節約される時間は次のようになります。
- DNS は一般に UDP プロトコルを使用しますが、最近 DNS の内容を見直したところ、DNS 応答メッセージの長さが 512 バイトを超える場合は TCP プロトコルが使用されます。実際、多くの DNS サーバーは UDP のみをサポートするように構成されています。したがって、このステップは 1 RTT を節約するとみなすことができます。
- TCP 接続を確立するには、3 ウェイ ハンドシェイクに 2 つの RTT が必要です。
- TLS 接続を確立するには、TLS バージョンに応じて異なる RTT が必要です。
HTTP バージョン 1.1 は、デフォルトで永続的な接続で開始します。これは再利用でき、メッセージのヘッダーに追加することConnection:Close
で。さらに、アイドル状態の永続接続はいつでも閉じることができます。たとえ送信されなかったとしてもConnection:Close
、サーバー接続が永久に開いたままになるわけではありません。
事前接続
OkHttp などの一般的に使用されるネットワーク フレームワークはすべて HTTP1.1 および HTTP2 機能をサポートしており、接続の多重化もサポートしています。
このメカニズムを使用して事前接続を行うことができます。たとえば、APP スプラッシュ画面が待機しているときに、キー ページのドメイン名の接続を事前に確立できるため、ユーザーが対応するページに入った後、ネットワークリクエストの結果をより速く取得できるようになり、ユーザーエクスペリエンスが向上します。
ドメイン名リンクに対する HEAD リクエスト (ボディなし) を事前に開始するだけで、事前に接続を確立でき、同じドメイン名に対する次のリクエストを直接再利用できます。
private val client by lazy { OkHttpClient() }
btn.setOnClickListener {
// 正式请求
launch(Dispatchers.IO) {
request()
}
}
// 预连接
launch(Dispatchers.IO) {
preRequest()
}
fun preRequest() {
val request = Request.Builder()
.head()
.url("xxx")
.build()
client.newCall(request).execute()
}
fun request() {
val request = Request.Builder()
.get()
.url("xxx/yyy")
.build()
client.newCall(request).execute()
}
パケットをキャプチャして、初めて入力したときに送信されたヘッド リクエストと、実際にクリックすることで送信された get リクエストを確認できます。
事前接続
正式なリクエスト
正式なリクエストを行う場合、上記の 3 つのステップにかかる時間が実際に短縮されることがわかります。接続と TLS に関する情報を個別に確認することもできます。
事前接続
正式なリクエスト
正式なリクエストを行うときに、これら 2 つが再利用されることがわかります (TLSSession Resumed
と接続のServer Connection
部分に注目します)。
また、OkHttp には ConnectionPool という接続プールがあり、Connect 接続を使用する場合、まず既存の接続が再利用され、使用可能な接続がなくなった場合に新しい接続が作成されます。接続プールの接続数には制限があり(デフォルトでは5つのようです)、業務が複雑でリクエストが多い場合、接続プールが満杯になり、以前に作成した事前接続が解放されることがあります。したがって、比較的簡単な方法は、接続プールの容量とタイムアウトを適切に増やすことです。
要約する
http(s) 接続多重化メカニズムを通じて、APP の特定のシナリオでネットワーク要求速度を最適化するために事前接続の使用を検討できます。これには、実際のビジネス シナリオとサーバーの負荷に応じて事前接続を実行するかどうかを判断する必要があります。
また、接続プールの容量とタイムアウトを適切に増やすことができ、接続は双方向であるため、クライアントが接続を維持した場合でも、サーバーは実際の接続数と接続時間に応じて自動的に接続を閉じます。接続プールを増やすのが一般的ですが、サーバーの負荷は増加しません。
事前接続の効果は、実際にはサーバー構成に関連しています。サーバーが接続タイムアウトを非常に小さく設定すると、リクエストごとに接続を再確立する必要が生じる可能性があるため、クライアントの事前接続が無効になり、サーバーは、代わりに継続的に TCP 接続を作成および破棄する必要もあります。より多くのリソースが無駄になります。サーバーが接続タイムアウトを大きな値に設定すると、以前の接続は長時間解放されず、同時サーバー サービスの数に影響します。新しいリクエストに影響を与えます。したがって、チューニングには複数端末の連携と総合的な検討が必要となります。
Androidの勉強メモ
Android パフォーマンスの最適化: https://qr18.cn/FVlo89
Android Vehicle: https://qr18.cn/F05ZCM
Android リバース セキュリティ調査ノート: https://qr18.cn/CQ5TcL
Android フレームワークの原則: https://qr18.cn/AQpN4J
Android オーディオとビデオ: https://qr18.cn/Ei3VPD
Jetpack (Compose を含む): https://qr18.cn/A0gajp
Kotlin: https://qr18.cn/CdjtAF
Gradle: https://qr18.cn/DzrmMB
OkHttp ソース コード分析ノート: https://qr18.cn/Cw0pBD
Flutter: https://qr18.cn/DIvKma
Android Eight Knowledge Body: https://qr18.cn/CyxarU
Android Core Notes: https://qr21.cn/CaZQLo
Android過去の面接の質問: https://qr18.cn/CKV8OZ
2023 年最新の Android 面接の質問集: https://qr18.cn/CgxrRy
Android 車両開発の就職面接の演習:https://qr18.cn/FTlyCJ
音声とビデオの面接の質問:https://qr18.cn/AcV6Ap