1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【具体例3つ】なぜWebページが表示される?【Webシステムの全体像】

Posted at

はじめに:なぜ、全体像を「自分の言葉で」説明する必要があるのか

Webサービスを作るにはプログラミングが必要ですが、コードだけで動いているわけではありません
その裏側には、ブラウザ・サーバー・データベース・通信の仕組みなど、いろんな要素が関わっています。

わたし自身も最初は「サーバーってなに?」「DBってどこにあるの?」「いま自分が書いているこのコード、Webサービス全体の中でどこに位置してるんだ?」という疑問にぶつかりました。
この疑問を解消するため、まずはWebサービスの全体像と、各コンポーネントがなぜ必要で、どう連携しているのかを理解することからスタートしました。
この記事では、Webシステムの全体像をざっくり整理しつつ、図と具体例でまとめます。
あくまで自分用の整理記事ですが、同じように学習している方の参考になれば幸いです。


全体像を知るメリット

  • 「今やってる作業が全体のどこに位置するのか?」を理解できる
  • 新しい技術を学ぶときに迷子になりにくい
  • チーム開発で「その処理はどのサーバー側で動く?」と会話がスムーズになる

Webシステムのざっくり構成図

まずは全体像を図で描いてみました。

[ブラウザ] ⇄ [Webサーバー] ⇄ [アプリケーション] ⇄ [DBサーバー]
  • ブラウザ:ユーザーの入り口。HTML/CSS/JSを表示。
  • Webサーバー:ApacheやNginxなど。リクエストを受けて、アプリに渡す。
  • アプリケーション:LaravelやRailsなど。ビジネスロジックを処理。
  • DBサーバー:MySQLやPostgreSQLなど。データを保存・取得。

この流れが分かっていれば、「今自分はどこを触ってるのか?」が見失いにくくなる。


「なぜ」Webサーバーとアプリケーションサーバーを分けるのか?

学習の中で最も腑に落ちたのが、サーバー側の役割分担です。「全部一つのプログラムで動かせばいいのでは?」という素朴な疑問がありました。

コンポーネント 役割 なぜ必要か(システムの安定性・効率性)
Webサーバー 静的コンテンツ(HTML, CSS, 画像)の配信 高速性・専門性:アプリケーションロジックを処理せず、ファイル配信に特化することで、大量のリクエストを迅速にさばく。
アプリケーションサーバー 動的コンテンツ(ユーザーデータに基づくHTMLなど)の生成、ビジネスロジックの実行 安全性・分離:ロジック部分をWebサーバーから分離し、外部からの不正なリクエストが直接ロジックに触れるのを防ぐ。負荷分散もしやすくなる。

具体例1:ブログサービス

ブログサービスの場合、ざっくりと以下のような処理が行われています。

  • Webサーバー:「お問い合わせ」ページのCSSファイル、サイトロゴ画像など、誰が見ても同じファイルを配信。
  • アプリケーションサーバー:ログインユーザーの「マイページ」や、データベースから記事一覧を取得して動的に生成するHTMLを処理。

この分離は、セキュリティやスケーラビリティを確保する上で必須だと理解しました。


具体例2:ログイン処理の流れ

より理解を深めるため、「ログイン画面からIDとパスワードを送信する」場合の処理の流れを図にしました。

1. **ブラウザ**

   * ユーザーが `email` と `password` を入力し、送信ボタンを押す。
   * 送信データは **HTTPリクエスト** としてサーバーに送られる。

2. **Webサーバー(例:Nginx, Apache)**

   * 受け取ったリクエストをアプリケーションに渡す。
   * ここは「交通整理役」。直接ロジックは書かない。

3. **アプリケーション(例:Laravel, Rails, Spring)**

   * コントローラーがリクエストを受け取り、入力値をチェック。
   * データベースに「そのユーザーが存在するか?」を問い合わせる。

4. **データベース(例:MySQL, PostgreSQL)**

   * `SELECT * FROM users WHERE email = ...` のようなクエリを実行。
   * 結果をアプリケーションに返す。

5. **アプリケーション**

   * パスワードを照合。正しければ「ログイン成功」としてセッションを発行。

6. **レスポンス**

   * Webサーバーを経由してブラウザに結果を返す。
   * 成功なら「マイページ画面のHTML」や「JSONレスポンス」が返る。

「通信の仕組み」を意識する:HTTPだけではない連係プレー

ブラウザとサーバー間の通信はHTTP(またはHTTPS)ですが、サーバー内部ではさらに専門的な通信が行われています。

  • ブラウザ $\leftrightarrow$ Webサーバー
    通常、この間はリバースプロキシが、クライアントからのリクエストを受け付け、バックエンドのWebサーバーに転送し、サーバーからの応答をクライアントに返す仲介役を担います。これにより、セキュリティの強化、Webサーバーへの負荷分散、パフォーマンスの最適化などを実現します。
  • アプリケーションサーバー $\leftrightarrow$ DBサーバー
    この間はSQLなどの専用プロトコルが使われます。データベースへの接続情報は外部に公開してはならないため、DBサーバーは外部からの直接アクセスを遮断し、アプリケーションサーバーと内部ネットワークでのみ通信するのが原則です。

現場での「なぜ?」を減らす視点:
データベース接続がうまくいかない場合、「アプリケーションのコードの問題」だけでなく、「DBサーバーのファイアウォール設定」や「アプリケーションサーバーからの内部通信が許可されているか」といったインフラレイヤーの視点が必要になります。この全体像の理解が、切り分け(デバッグ)のスピードを決定づけます。


さらに必要になる要素

Webサービスが本番で動くには、これ以外にも多くの要素が絡みます。

  • ドメイン・DNS
    → 「example.com」がどのサーバーを指すかを解決する仕組み。
  • セキュリティ
    → HTTPSによる暗号化、SQLインジェクション対策、CSRF対策など。
  • インフラ
    → サーバーはクラウド(AWS, GCP, Azure)に置かれることが多い。
  • キャッシュ
    → 毎回DBに問い合わせず、メモリ上に結果を保存して高速化。

具体例3:Webページ表示の流れ

表題の疑問を解消するべく、以下の処理の流れを図にしました。
「ブラウザにURLを入力してEnterを押すと、なぜページが表示されるのか?」

[ユーザー]
    ↓ URL入力
[Webブラウザ(Chrome等)]
    ↓ HTTPリクエスト(https://example.com/login)
    ↓ ① DNS問い合わせ → IPアドレス取得
    ↓ ② TCP接続確立(3ウェイハンドシェイク)
    ↓ ③ SSL/TLS通信開始(暗号化)
    │
[インターネット]
    │
[ファイアウォール]
    ↓ 不正アクセス遮断
[ロードバランサー]
    ↓ 複数サーバーに負荷分散
    │
┌───┴───┬───────┐
│       │       │
[Webサーバー1] [Webサーバー2] [Webサーバー3]
(Nginx/Apache)
    ↓
[アプリケーションサーバー]
(Rails/Django/Node.js等)
    ↓ ビジネスロジック実行
    ├→ [キャッシュサーバー] (Redis/Memcached)
    │   └→ よく使うデータを高速取得
    │
    └→ [DBサーバー](MySQL/PostgreSQL)
        └→ ユーザー情報、投稿データ等を永続化
    
    ↓ HTMLレンダリング
[Webサーバー]
    ↓ HTTPレスポンス(HTML/CSS/JS)
[Webブラウザ]
    ↓ 画面描画
[ユーザー]

各コンポーネントの役割を具体例で理解する

1. DNSサーバー:住所録のようなもの

何をしているか
example.comというドメイン名を203.0.113.45というIPアドレスに変換します。

なぜ必要か
コンピュータ同士は数字のIPアドレスで通信しますが、人間には覚えにくい。だから「google.com」のような名前で管理しています。電話帳で「山田さん」を探して電話番号を調べるのと同じです。

具体的な動き

  1. ブラウザが「example.comのIPアドレスは?」と問い合わせ
  2. DNSサーバーが「203.0.113.45だよ」と返答
  3. ブラウザはそのIPアドレスに接続

2. Webサーバー:受付係

何をしているか
HTTPリクエストを受け取り、静的ファイル(HTML/CSS/画像)を返したり、動的な処理をアプリケーションサーバーに渡したりします。

なぜ必要か
アプリケーションサーバーは複雑な処理をするため重い。単純な画像配信などはWebサーバーが高速に処理したほうが効率的です。レストランで例えるなら、ホールスタッフ(Webサーバー)が注文を受けて、簡単なドリンクはその場で出し、料理はキッチン(アプリケーションサーバー)に回すイメージ。

具体的な動き

  • /style.cssへのリクエスト → そのままCSSファイルを返す
  • /api/usersへのリクエスト → アプリケーションサーバーに転送

3. アプリケーションサーバー:料理人

何をしているか
ビジネスロジックを実行します。ログイン処理、投稿の保存、検索処理など、Webサービスの核となる処理を担当。

なぜ必要か
「このユーザーは本人か?」「この操作は許可されているか?」「データをどう加工するか?」といった複雑な判断が必要だから。

具体的な動き(ログイン処理の例)

  1. POSTでemail=user@example.com, password=secret123を受信
  2. DBからemailに一致するユーザーを検索
  3. パスワードをハッシュ化して保存されているものと照合
  4. 一致したらセッションIDを生成
  5. CookieにセッションIDをセットしてレスポンス

4. データベースサーバー:倉庫

何をしているか
データを永続化します。ユーザー情報、投稿、コメント、いいねなど、すべてのデータを保存。

なぜ必要か
メモリ上のデータはサーバーを再起動すると消えてしまいます。ディスクに保存することで、電源を切ってもデータが残ります。また、複雑な検索(「東京都に住む20代のユーザーで、最近1週間投稿していない人」など)を高速に実行できます。

具体的な動き

SELECT * FROM users WHERE email = 'user@example.com';

このようなSQL文でデータを取得・更新します。

5. キャッシュサーバー:よく使うものを手元に置く

何をしているか
頻繁にアクセスされるデータをメモリ上に一時保存します。

なぜ必要か
DBへの問い合わせは遅い(ディスクI/O)。トップページのランキングなど、全ユーザーが同じデータを見る場合、毎回DBに問い合わせるのは無駄です。

具体的な動き

  1. ランキング情報をリクエスト
  2. まずRedisに「ranking_dataあるか?」確認
  3. あればそれを返す(高速)
  4. なければDBから取得してRedisに保存(次回から高速化)

なぜ複数のサーバーに分けるのか?

理由1:役割分担で効率化

料理でも、切る人・炒める人・盛り付ける人と分業したほうが早い。同じように、静的ファイル配信・ビジネスロジック実行・データ保存を別サーバーにすると効率的です。

理由2:スケーラビリティ

アクセスが急増したとき、ボトルネックになっている部分だけサーバーを増やせます。例えば、計算処理が重ければアプリケーションサーバーだけ5台に増やす、といった対応が可能。

理由3:障害対応

1つのサーバーがダウンしても、他のサーバーでカバーできます。DBサーバーが落ちてもキャッシュサーバーから一部データを返せる、など。

代表的なセキュリティ:なぜ「通信の暗号化」「DBの隔離」が重要?

全体像を理解すると、セキュリティ対策の「なぜ」も見えてきます。

HTTPS通信(SSL/TLS)

ブラウザとWebサーバー間の通信を暗号化します。これにより、途中の盗聴者がクレジットカード情報やCookie、パスワードなどの機密情報を読み取るのを防げます。

具体例

  • ブラウザとサーバー間でSSL証明書を交換
  • 共通の暗号鍵を生成
  • 以降の通信をすべて暗号化

DBサーバーの隔離

DBサーバーを外部ネットワークから完全に隔離することで、仮にWebサーバーやアプリケーションサーバーが攻撃されても、データそのものを保護する最後の砦となります。

ファイアウォール

特定のIPアドレスやポート以外からのアクセスを遮断。

具体例

  • ポート80(HTTP)と443(HTTPS)だけ開放
  • SSH(ポート22)は社内IPからのみ許可
  • 不審なIPからの大量アクセスをブロック

アプリケーション層のセキュリティ

  • SQLインジェクション対策:ユーザー入力をエスケープ
  • XSS対策:HTMLタグを無効化
  • CSRF対策:トークンで正規リクエストか確認

具体例(SQLインジェクション)

// 危険な例
query = "SELECT * FROM users WHERE email = '" + user_input + "'"
// user_inputに "' OR '1'='1" を入れると全ユーザー情報が漏洩

// 安全な例(プリペアドステートメント)
query = "SELECT * FROM users WHERE email = ?"
execute(query, [user_input]) // 自動的にエスケープされる

実際にリクエストを送ってみる

理解を深めるため、ターミナルでHTTPリクエストを送ってみました。

curl -v https://example.com/

レスポンスの一部

> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.68.0
> 
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Content-Length: 1256
< 
<!DOCTYPE html>
<html>
...

この>がリクエスト、<がレスポンスです。実際にどんなデータをやり取りしているか目で見ると理解が深まりました。

まとめ:全体像を把握する重要性

図を描いてみることで、以下が腹落ちしました。

  1. 各技術の存在理由:なぜNginxが必要か、なぜRedisを使うか、点ではなく線で理解できた
  2. トラブル時の切り分け:「画面が表示されない」→どこに原因があるか推測できる(DNS?Webサーバー?DB?)
  3. 学習の優先順位:今自分はどこを学んでいるか地図がある状態で進められる

まだまだ浅い理解ですが、これをベースに実際に手を動かしてWebサービスを作りながら深めていきます。

参考にした書籍

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?