はじめに:なぜ、全体像を「自分の言葉で」説明する必要があるのか
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」のような名前で管理しています。電話帳で「山田さん」を探して電話番号を調べるのと同じです。
具体的な動き
- ブラウザが「example.comのIPアドレスは?」と問い合わせ
- DNSサーバーが「203.0.113.45だよ」と返答
- ブラウザはそのIPアドレスに接続
2. Webサーバー:受付係
何をしているか
HTTPリクエストを受け取り、静的ファイル(HTML/CSS/画像)を返したり、動的な処理をアプリケーションサーバーに渡したりします。
なぜ必要か
アプリケーションサーバーは複雑な処理をするため重い。単純な画像配信などはWebサーバーが高速に処理したほうが効率的です。レストランで例えるなら、ホールスタッフ(Webサーバー)が注文を受けて、簡単なドリンクはその場で出し、料理はキッチン(アプリケーションサーバー)に回すイメージ。
具体的な動き
-
/style.css
へのリクエスト → そのままCSSファイルを返す -
/api/users
へのリクエスト → アプリケーションサーバーに転送
3. アプリケーションサーバー:料理人
何をしているか
ビジネスロジックを実行します。ログイン処理、投稿の保存、検索処理など、Webサービスの核となる処理を担当。
なぜ必要か
「このユーザーは本人か?」「この操作は許可されているか?」「データをどう加工するか?」といった複雑な判断が必要だから。
具体的な動き(ログイン処理の例)
- POSTで
email=user@example.com, password=secret123
を受信 - DBからemailに一致するユーザーを検索
- パスワードをハッシュ化して保存されているものと照合
- 一致したらセッションIDを生成
- CookieにセッションIDをセットしてレスポンス
4. データベースサーバー:倉庫
何をしているか
データを永続化します。ユーザー情報、投稿、コメント、いいねなど、すべてのデータを保存。
なぜ必要か
メモリ上のデータはサーバーを再起動すると消えてしまいます。ディスクに保存することで、電源を切ってもデータが残ります。また、複雑な検索(「東京都に住む20代のユーザーで、最近1週間投稿していない人」など)を高速に実行できます。
具体的な動き
SELECT * FROM users WHERE email = 'user@example.com';
このようなSQL文でデータを取得・更新します。
5. キャッシュサーバー:よく使うものを手元に置く
何をしているか
頻繁にアクセスされるデータをメモリ上に一時保存します。
なぜ必要か
DBへの問い合わせは遅い(ディスクI/O)。トップページのランキングなど、全ユーザーが同じデータを見る場合、毎回DBに問い合わせるのは無駄です。
具体的な動き
- ランキング情報をリクエスト
- まずRedisに「ranking_dataあるか?」確認
- あればそれを返す(高速)
- なければ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>
...
この>
がリクエスト、<
がレスポンスです。実際にどんなデータをやり取りしているか目で見ると理解が深まりました。
まとめ:全体像を把握する重要性
図を描いてみることで、以下が腹落ちしました。
- 各技術の存在理由:なぜNginxが必要か、なぜRedisを使うか、点ではなく線で理解できた
- トラブル時の切り分け:「画面が表示されない」→どこに原因があるか推測できる(DNS?Webサーバー?DB?)
- 学習の優先順位:今自分はどこを学んでいるか地図がある状態で進められる
まだまだ浅い理解ですが、これをベースに実際に手を動かしてWebサービスを作りながら深めていきます。