1回のリクエストの完全な旅
はじめに
ブラウザにURLを入力してEnterキーを押してから、ページが表示されるまで、その間に一体何が起きているのか? この質問は面接の定番であると同時に、Webアーキテクチャ全体を理解する鍵でもあります。この経路を理解すれば、フロントエンド、バックエンド、ネットワーク、データベースがどのように連携しているかがわかります。
この記事で学べること
この章を学び終えると、次の能力が身につきます:
- 全経路の視点:HTTPリクエストが送信されてから返ってくるまでの完全なプロセスを理解
- 各層の責務認識:DNS、TCP、ロードバランサー、Webサーバー、アプリケーションサーバー、データベースがそれぞれ何をするかを理解
- 問題特定能力:リクエストが遅いか失敗したときに、どの層から調査を始めるべきかがわかる
- パフォーマンス最適化の考え方:各層に最適化の余地があり、最適化ポイントがどこにあるかを理解
| 章 | 内容 | コアコンセプト |
|---|---|---|
| 第1章 | ブラウザがリクエストを発信 | DNS解決、TCP接続、HTTPリクエスト |
| 第2章 | ネットワーク転送 | ルーティング、CDN、ロードバランシング |
| 第3章 | サーバー処理 | Webサーバー、アプリケーションロジック、データベースクエリ |
| 第4章 | レスポンス返却 | シリアライズ、圧縮、レンダリング |
| 第5章 | 全経路最適化 | キャッシュ、接続再利用、非同期処理 |
0. 全景図:1回のリクエストは何を経験するのか?
例えで理解しましょう:ネットで本を注文するプロセスは、HTTPリクエストと驚くほど似ています。
| リクエスト段階 | 本の購入の例え | 技術的対応 |
|---|---|---|
| URL入力 | 「○○書店に行きたい」と言う | ブラウザがURLを解析 |
| DNS解決 | 地図で書店の住所を調べる | ドメイン名 → IPアドレス |
| TCP接続 | 書店の前に歩いて行き、ドアを開けて入る | スリーウェイハンドシェイクで接続確立 |
| リクエスト送信 | 店員に「○○という本をください」と伝える | HTTPリクエストメッセージ |
| サーバー処理 | 店員が倉庫に本を探しに行き、在庫確認、価格計算 | アプリケーションロジック + データベースクエリ |
| レスポンス返却 | 店員が本を渡す | HTTPレスポンスメッセージ |
| ブラウザレンダリング | 本を開いて読み始める | HTML/CSS/JS解析レンダリング |
1. ブラウザがリクエストを発信
1.1 URL解析
https://api.example.com/books?id=123 と入力すると、ブラウザはそれをいくつかの部分に分解します:
| 部分 | 値 | 意味 |
|---|---|---|
| プロトコル | https | 暗号化方式で通信 |
| ドメイン名 | api.example.com | サーバーの「名前」 |
| パス | /books | アクセスするリソース |
| クエリパラメータ | id=123 | 追加条件 |
1.2 DNS解決:ドメイン名 → IPアドレス
コンピュータはドメイン名を認識せず、IPアドレス(例:93.184.216.34)だけを認識します。DNSはインターネットの「電話帳」です。
ブラウザキャッシュ → システムキャッシュ → ルーターキャッシュ → ISP DNS → ルートドメインネームサーバー
↓ ヒットすれば直接使用、ヒットしなければ下へ検索DNSキャッシュの意義
毎回のリクエストでルートドメインネームサーバーから検索を始めると、世界中のインターネットがDNSクエリで押し潰されてしまいます。そのため各層にキャッシュがあり、ほとんどのリクエストはブラウザやシステム層で解決が完了します。
1.3 TCPスリーウェイハンドシェイク
IPアドレスを見つけた後、ブラウザはサーバーと「接続を確立」する必要があります。TCPはスリーウェイハンドシェイクで双方の準備ができていることを確認します:
クライアント → サーバー:こんにちは、接続したいです(SYN)
サーバー → クライアント:はい、準備できました(SYN + ACK)
クライアント → サーバー:受信しました、通信を開始します(ACK)HTTPSの場合、暗号化方式をネゴシエーションするための追加のTLSハンドシェイクも必要です。
1.4 HTTPリクエストの送信
接続が確立されると、ブラウザはHTTPリクエストメッセージを送信します:
GET /books?id=123 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGci...
User-Agent: Chrome/120.0| 構成部分 | 内容 |
|---|---|
| リクエストライン | メソッド(GET)+ パス + プロトコルバージョン |
| リクエストヘッダー | メタ情報:身元認証、期待するデータ形式など |
| リクエストボディ | POST/PUTリクエストのみ存在。送信するデータを含む |
2. ネットワーク転送:リクエストは道中
2.1 ルーティング転送
リクエストがあなたのコンピュータを離れた後、複数のルーターを経由して転送されます。宅配便が複数の中継所を経由するのと同じです:
あなたのPC → 家庭用ルーター → 通信事業者ネットワーク → バックボーンネットワーク → 対象データセンター各ルーターはIPアドレスに基づいて「次のホップ」をどこに転送するかを決定します。traceroute コマンドでリクエストがどのノードを経由したかを確認できます。
2.2 CDN高速化
対象のWebサイトがCDN(コンテンツ配信ネットワーク)を使用している場合、リクエストはオリジンサーバーまで到達する必要がない場合があります:
| シーン | 経路 |
|---|---|
| 静的リソースのリクエスト(画像、CSS、JS) | CDNエッジノードが直接返却 |
| 動的データのリクエスト(API) | CDNを通過し、オリジンサーバーに到達 |
CDNの本質は「コンテンツを事前にユーザーに最も近い場所に配置する」ことです。
2.3 ロードバランシング
大規模なWebサイトは1台のサーバーだけではありません。ロードバランサーがリクエストを複数のサーバーに振り分けます:
ユーザーリクエスト → ロードバランサー → サーバーA(30%のトラフィック)
→ サーバーB(30%のトラフィック)
→ サーバーC(40%のトラフィック)よく使われる振り分け戦略:
| 戦略 | 原理 | 適したシーン |
|---|---|---|
| ラウンドロビン | 順番に振り分け | サーバー構成が同じ |
| 重み付きラウンドロビン | 重みに応じて振り分け | サーバー構成が異なる |
| IPハッシュ | 同一ユーザーを固定のサーバーに | セッション維持が必要 |
| 最小接続数 | 現在の接続が最も少ないサーバーに | リクエスト処理時間の差が大きい |
3. サーバー処理:厨房で何が起きているか
リクエストがサーバーに到着した後、複数の層で処理されます。
3.1 Webサーバー(Nginx / Apache)
最初にリクエストを受け取るのは通常Webサーバーで、以下の役割を担います:
| 責務 | 説明 |
|---|---|
| 静的ファイル配信 | HTML、CSS、JS、画像を直接返却 |
| リバースプロキシ | APIリクエストをバックエンドアプリケーションに転送 |
| SSL終端 | HTTPS暗号化/復号を処理 |
| リクエストフィルタリング | 悪意のあるリクエストの遮断、レート制限 |
3.2 アプリケーションサーバー処理
Webサーバーがリクエストをアプリケーションサーバー(Node.js、Spring、Djangoなど)に転送し、処理フローは以下の通りです:
リクエスト到着 → ミドルウェアチェーン → ルートマッチング → コントローラー → サービス層 → データアクセス層ミドルウェアが行うこと:
- リクエストボディの解析(JSON、フォームデータ)
- 身元確認(Tokenのチェック)
- 権限チェック(このユーザーはこのインターフェースにアクセスできるか?)
- ログ記録(誰がいつ何にアクセスしたか)
3.3 データベースクエリ
ほとんどのリクエストは最終的にデータベースとやり取りします:
アプリケーションコード:SELECT * FROM books WHERE id = 123
↓
データベースエンジン:SQL解析 → クエリ最適化 → 実行計画 → データ読み取り
↓
結果返却:{ id: 123, title: "xxx", price: 59.9 }データベースが最も一般的なパフォーマンスボトルネック
ネットワーク転送は通常ミリ秒単位、アプリケーションロジックも高速ですが、インデックスのないデータベースクエリは数秒から数十秒かかることがあります。そのため「遅いリクエスト」は大抵データベースクエリが遅いことが原因です。
4. レスポンス返却:データの帰路
4.1 HTTPレスポンスの構築
サーバーが処理を完了すると、レスポンスメッセージを構築します:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Cache-Control: max-age=3600
{"id": 123, "title": "xxx", "price": 59.9}| 構成部分 | 内容 |
|---|---|
| ステータスライン | プロトコルバージョン + ステータスコード(200成功、404未検出、500サーバーエラー) |
| レスポンスヘッダー | データ形式、キャッシュ戦略、圧縮方式など |
| レスポンスボディ | 実際のデータ内容(JSON、HTMLなど) |
4.2 データ圧縮
サーバーは通常gzipまたはbrotliでレスポンスボディを圧縮し、転送量を削減します:
| 圧縮アルゴリズム | 圧縮率 | 速度 |
|---|---|---|
| gzip | 約70% | 速い |
| brotli | 約80% | やや遅いが圧縮率が高い |
100KBのJSONも圧縮後は20-30KBになることがあります。
4.3 ブラウザレンダリング
ブラウザがレスポンスを受信した後:
- HTML解析 → DOMツリー構築
- CSS解析 → スタイルツリー構築
- 統合 → レンダリングツリー生成
- レイアウト → 各要素の位置とサイズを計算
- 描画 → ピクセルを画面に描画
5. 全経路最適化:各層でより速く
5.1 各層の最適化手段
| 層 | 最適化手段 | 効果 |
|---|---|---|
| DNS | DNSプリフェッチ、高速DNSサービスの使用 | DNSクエリ時間の削減 |
| ネットワーク | CDN、HTTP/2、接続再利用 | 転送遅延の削減 |
| サーバー | キャッシュ(Redis)、非同期処理 | 処理時間の削減 |
| データベース | インデックス、クエリ最適化、読み書き分離 | クエリ時間の削減 |
| フロントエンド | 遅延読み込み、コード分割、リソース圧縮 | レンダリング時間の削減 |
5.2 キャッシュ:最も効果的な最適化
キャッシュはリクエスト経路の各層に存在します:
ブラウザキャッシュ → CDNキャッシュ → リバースプロキシキャッシュ → アプリケーションキャッシュ(Redis)→ データベースキャッシュキャッシュの本質
空間を時間と交換する。計算済みの結果を保存し、次回は直接使用し、再計算しません。キャッシュヒット率が10%向上するごとに、システムパフォーマンスは数倍向上する可能性があります。
5.3 リクエスト失敗時の調査手順
| 現象 | 問題の可能性がある層 | 調査方法 |
|---|---|---|
| 完全に応答なし | DNS / ネットワーク | ping、nslookup |
| 接続タイムアウト | ネットワーク / サーバーダウン | telnet、curl |
| 4xx 返却 | クライアントリクエストに誤り | URL、パラメータ、Tokenを確認 |
| 5xx 返却 | サーバー内部エラー | サーバーログを確認 |
| 応答が非常に遅い | データベース / アプリケーションロジック | スロークエリログ、APMツールを確認 |
6. まとめ
1回のHTTPリクエストの完全な旅:
- ブラウザ:URL解析 → DNSクエリ → TCP接続 → リクエスト送信
- ネットワーク:ルーティング転送 → CDN判断 → ロードバランシング振り分け
- サーバー:Webサーバー受信 → ミドルウェア処理 → ビジネスロジック → データベースクエリ
- 返却:レスポンス構築 → 圧縮 → ネットワーク転送 → ブラウザレンダリング
全経路を理解する価値
リクエストの完全な経路を頭の中で描けるようになると、どんな問題が発生しても、どの層で問題が起きているかを素早く特定できます。これは「初級開発者」から「自立して問題調査ができる」への重要な飛躍です。
参考資料
- HTTP 権威ガイド — MDNのHTTPドキュメント
- High Performance Browser Networking — ブラウザネットワークパフォーマンス最適化
- What happens when... — 古典的な「URL入力後に何が起きるか」の詳細解説