目次
はじめに——ネットワークは「レイヤーの積み重ね」
コンピューターネットワークは、現代インターネットの物理的な基盤だ。Web ブラウジング、メール、動画配信、クラウドコンピューティング——これらすべてがネットワークプロトコルの上に成り立っている。
本記事の核心的な主張は以下の通りだ:
コンピューターネットワークは『レイヤー化されたプロトコルの積み重ね』によって成立している。各レイヤーの役割と、パケットがどのようにカプセル化され、宛先まで配送されるかを理解することは、分散システム設計の前提条件だ。
このレイヤー化されたアーキテクチャを理解することは、TLS/SSL の仕組み、CDN のキャッシュ戦略、マイクロサービス間の通信、そしてクラウドネイティブアーキテクチャを理解する上でも不可欠だ。
ネットワークの基本概念——OSI 参照モデルと TCP/IP
OSI 参照モデル——7 層のレイヤー
**OSI 参照モデル(Open Systems Interconnection Reference Model)**は、ネットワーク機能を 7 つのレイヤーに分割した概念モデルだ。
【OSI 参照モデルの 7 層】
第 7 層:アプリケーション層 (Application Layer)
- HTTP, HTTPS, DNS, SMTP, SSH
- エンドユーザーのアプリケーションへのサービス提供
第 6 層:プレゼンテーション層 (Presentation Layer)
- データのエンコード・デコード
- 暗号化・復号(SSL/TLS)
- 圧縮・解凍
第 5 層:セッション層 (Session Layer)
- 通信セッションの確立・維持・終了
- 認証・許可
第 4 層:トランスポート層 (Transport Layer)
- TCP, UDP
- エンドツーエンドの通信制御
- 信頼性(再送制御)、フロー制御
第 3 層:ネットワーク層 (Network Layer)
- IP(インターネットプロトコル)
- パケットのルーティング
- アドレッシング(IP アドレス)
第 2 層:データリンク層 (Data Link Layer)
- イーサネット、Wi-Fi
- フレームの送受信
- MAC アドレス
第 1 層:物理層 (Physical Layer)
- 電気信号、光信号
- ケーブル、ハブ、リピータ
核心: 各レイヤーは「下のレイヤーのサービスを利用し、上のレイヤーにサービスを提供する」。このカプセル化によって、各レイヤーは独立して進化できる。
TCP/IP モデル——実質的な標準
現代インターネットで実際に使用されているのは、TCP/IP モデル(4 層)だ。
def explain_tcp_ip_layers():
"""
TCP/IP モデルの 4 層解説
"""
layers = {
'アプリケーション層': {
'proTOCOLS': ['HTTP', 'HTTPS', 'DNS', 'SMTP', 'SSH', 'FTP'],
'role': 'アプリケーション固有の通信プロトコル',
'data_unit': 'データ(Data)',
'example': 'Web ブラウザが HTTP リクエストを生成'
},
'トランスポート層': {
'proTOCOLS': ['TCP', 'UDP'],
'role': 'エンドツーエンドの通信制御',
'data_unit': 'セグメント(TCP)/ データグラム(UDP)',
'example': 'ポート番号でアプリケーションを識別、信頼性制御'
},
'インターネット層': {
'proTOCOLS': ['IP', 'ICMP', 'ARP'],
'role': 'パケットのルーティング',
'data_unit': 'パケット(Packet)',
'example': 'IP アドレスで宛先を指定、ルート選択'
},
'ネットワークインターフェース層': {
'proTOCOLS': ['イーサネット', 'Wi-Fi', 'PPP'],
'role': '物理的なデータ伝送',
'data_unit': 'フレーム(Frame)',
'example': 'MAC アドレスで隣接ノードへ配送'
}
}
print("【TCP/IP モデルの 4 層】\n")
for layer_name, layer_data in layers.items():
print(f"■ {layer_name}")
print(f" プロトコル:{', '.join(layer_data['proTOCOLS'])}")
print(f" 役割:{layer_data['role']}")
print(f" データ単位:{layer_data['data_unit']}")
print(f" 例:{layer_data['example']}\n")
explain_tcp_ip_layers()
出力:
【TCP/IP モデルの 4 層】
■ アプリケーション層
プロトコル:HTTP, HTTPS, DNS, SMTP, SSH, FTP
役割:アプリケーション固有の通信プロトコル
データ単位:データ(Data)
例:Web ブラウザが HTTP リクエストを生成
■ トランスポート層
プロトコル:TCP, UDP
役割:エンドツーエンドの通信制御
データ単位:セグメント(TCP)/ データグラム(UDP)
例:ポート番号でアプリケーションを識別、信頼性制御
■ インターネット層
プロトコル:IP, ICMP, ARP
役割:パケットのルーティング
データ単位:パケット(Packet)
例:IP アドレスで宛先を指定、ルート選択
■ ネットワークインターフェース層
プロトコル:イーサネット、Wi-Fi、PPP
役割:物理的なデータ伝送
データ単位:フレーム(Frame)
例:MAC アドレスで隣接ノードへ配送
核心: データは「アプリケーション層 → トランスポート層 → インターネット層 → ネットワークインターフェース層」とカプセル化され、物理媒体を流れる。
トランスポート層——TCP と UDP の使い分け
TCP(Transmission Control Protocol)
TCPは、信頼性の高いコネクション型プロトコルだ。
【TCP の主要な特性】
1. コネクション確立(3 ウェイハンドシェイク)
Client Server
│ │
│────── SYN ──────────────────→│
│ │
│←───── SYN-ACK ───────────────│
│ │
│────── ACK ──────────────────→│
│ │
確立 確立
2. 信頼性制御
- シーケンス番号(順序制御)
- 確認応答(ACK)と再送
- チェックサム(エラー検出)
3. フロー制御
- ウィンドウ制御(輻輳回避)
- 送りすぎ防止
4. コネクション終了(4 ウェイハンドシェイク)
- FIN フラグによる正常終了
UDP(User Datagram Protocol)
UDPは、信頼性のないコネクションレス型プロトコルだ。
def compare_tcp_udp(use_case: str) -> dict:
"""
TCP と UDP の比較と使い分け
"""
characteristics = {
'TCP': {
'connection': 'コネクション型(3 ウェイハンドシェイク)',
'reliability': 'あり(再送制御、順序制御)',
'speed': '遅め(オーバーヘッド大)',
'ordering': '順序保証あり',
'flow_control': 'あり(ウィンドウ制御)',
'use_cases': [
'Web ブラウジング(HTTP/HTTPS)',
'メール送信(SMTP)',
'ファイル転送(FTP)',
'リモートシェル(SSH)',
'データベース接続'
]
},
'UDP': {
'connection': 'コネクションレス(事前確立不要)',
'reliability': 'なし(ベストエフォート)',
'speed': '速い(オーバーヘッド小)',
'ordering': '順序保証なし',
'flow_control': 'なし',
'use_cases': [
'動画ストリーミング(欠落よりリアルタイム性)',
'VoIP・ビデオ会議',
'オンラインゲーム',
'DNS クエリ',
'SNMP(ネットワーク監視)'
]
}
}
return characteristics.get(use_case.upper(), {})
# 使用例
print("【TCP の特性】")
tcp = compare_tcp_udp('tcp')
for key, value in tcp.items():
if key != 'use_cases':
print(f" {key}: {value}")
print(" 用途例:")
for use in tcp['use_cases']:
print(f" - {use}")
print("\n【UDP の特性】")
udp = compare_tcp_udp('udp')
for key, value in udp.items():
if key != 'use_cases':
print(f" {key}: {value}")
print(" 用途例:")
for use in udp['use_cases']:
print(f" - {use}")
出力:
【TCP の特性】
connection: コネクション型(3 ウェイハンドシェイク)
reliability: あり(再送制御、順序制御)
speed: 遅め(オーバーヘッド大)
ordering: 順序保証あり
flow_control: あり(ウィンドウ制御)
用途例:
- Web ブラウジング(HTTP/HTTPS)
- メール送信(SMTP)
- ファイル転送(FTP)
- リモートシェル(SSH)
- データベース接続
【UDP の特性】
connection: コネクションレス(事前確立不要)
reliability: なし(ベストエフォート)
speed: 速い(オーバーヘッド小)
ordering: 順序保証なし
flow_control: なし
用途例:
- 動画ストリーミング(欠落よりリアルタイム性)
- VoIP・ビデオ会議
- オンラインゲーム
- DNS クエリ
- SNMP(ネットワーク監視)
核心: データの完全性が必要なら TCP、リアルタイム性が重要なら UDP を選択する。
アプリケーション層プロトコル——HTTP の進化
HTTP/1.1 → HTTP/2 → HTTP/3
HTTP は Web の基盤プロトコルとして進化を続けている。
【HTTP の進化】
HTTP/1.1(1997 年)
├─ テキストベースのプロトコル
├─ 1 コネクションで 1 リクエスト(直列処理)
│ → ヘッドオブロッキング問題
├─ Keep-Alive でコネクション再利用
└─ 課題:レイテンシ大、リソース競合
HTTP/2(2015 年)
├─ バイナリプロトコル(効率的なパース)
├─ マルチプレキシング(1 コネクションで並列処理)
├─ サーバープッシュ(先読み送信)
├─ ヘッダー圧縮(HPACK)
└─ 改善:レイテンシ削減、パフォーマンス向上
HTTP/3(2022 年)
├─ 転送プロトコルに UDP 使用(QUIC プロトコル)
├─ TCP 不要(0-RTT コネクション確立)
├─ ヘッドオブロッキングの完全解消
└─ 改善:モバイル環境でのパフォーマンス向上
HTTP メソッドとステータスコード
from typing import Dict, List
def http_reference() -> Dict[str, List[Dict]]:
"""
HTTP メソッドとステータスコードのリファレンス
"""
return {
'methods': [
{'method': 'GET', 'idempotent': True, 'body': False, 'description': 'リソースの取得'},
{'method': 'POST', 'idempotent': False, 'body': True, 'description': 'リソースの作成'},
{'method': 'PUT', 'idempotent': True, 'body': True, 'description': 'リソースの更新(全体)'},
{'method': 'PATCH', 'idempotent': False, 'body': True, 'description': 'リソースの部分的な更新'},
{'method': 'DELETE', 'idempotent': True, 'body': False, 'description': 'リソースの削除'},
{'method': 'HEAD', 'idempotent': True, 'body': False, 'description': 'ヘッダーのみ取得'},
{'method': 'OPTIONS', 'idempotent': True, 'body': False, 'description': '利用可能なメソッドの取得'}
],
'status_codes': {
'2xx(成功)': [
(200, 'OK', 'リクエスト成功'),
(201, 'Created', 'リソース作成成功'),
(204, 'No Content', '成功だが返すデータなし')
],
'3xx(リダイレクト)': [
(301, 'Moved Permanently', '恒久的なリダイレクト'),
(302, 'Found', '一時的なリダイレクト'),
(304, 'Not Modified', 'キャッシュ使用可')
],
'4xx(クライアントエラー)': [
(400, 'Bad Request', '不正なリクエスト'),
(401, 'Unauthorized', '認証が必要'),
(403, 'Forbidden', 'アクセス権限なし'),
(404, 'Not Found', 'リソースが見つからない'),
(429, 'Too Many Requests', 'レート制限')
],
'5xx(サーバーエラー)': [
(500, 'Internal Server Error', 'サーバー内部エラー'),
(502, 'Bad Gateway', 'ゲートウェイエラー'),
(503, 'Service Unavailable', 'サービス利用不可'),
(504, 'Gateway Timeout', 'ゲートウェイタイムアウト')
]
}
}
# 使用例
ref = http_reference()
print("【HTTP メソッド】")
print(f"{'メソッド':<10} | {'冪等性':<8} | {'ボディ':<8} | {'説明'}")
print("-" * 50)
for m in ref['methods']:
idemp = 'あり' if m['idempotent'] else 'なし'
body = '可' if m['body'] else '不可'
print(f"{m['method']:<10} | {idemp:<8} | {body:<8} | {m['description']}")
print("\n【HTTP ステータスコード(主要)】")
for category, codes in ref['status_codes'].items():
print(f"\n{category}:")
for code, name, desc in codes:
print(f" {code} {name}: {desc}")
出力:
【HTTP メソッド】
メソッド | 冪等性 | ボディ | 説明
--------------------------------------------------
GET | あろう | 不可 | リソースの取得
POST | なし | 可 | リソースの作成
PUT | あろう | 可 | リソースの更新(全体)
PATCH | なし | 可 | リソースの部分的な更新
DELETE | あろう | 不可 | リソースの削除
HEAD | あろう | 不可 | ヘッダーのみ取得
OPTIONS | あろう | 不可 | 利用可能なメソッドの取得
【HTTP ステータスコード(主要)】
2xx(成功):
200 OK: リクエスト成功
201 Created: リソース作成成功
204 No Content: 成功だが返すデータなし
3xx(リダイレクト):
301 Moved Permanently: 恒久的なリダイレクト
302 Found: 一時的なリダイレクト
304 Not Modified: キャッシュ使用可
4xx(クライアントエラー):
400 Bad Request: 不正なリクエスト
401 Unauthorized: 認証が必要
403 Forbidden: アクセス権限なし
404 Not Found: リソースが見つからない
429 Too Many Requests: レート制限
5xx(サーバーエラー):
500 Internal Server Error: サーバー内部エラー
502 Bad Gateway: ゲートウェイエラー
503 Service Unavailable: サービス利用不可
504 Gateway Timeout: ゲートウェイタイムアウト
核心: **冪等性(Idempotency)**を理解することは、リトライセーフな API 設計に不可欠だ。
DNS(Domain Name System)——インターネットの電話帳
DNS の階層構造
DNSは、ドメイン名(example.com)を IP アドレス(93.184.216.34)に変換するシステムだ。
【DNS の階層構造】
.(ルート)
/ | \
/ | \
.com .net .org ...(TLD)
/ | \
example.com ... ...(ドメイン)
/ \
/ \
www api mail(サブドメイン)
DNS 解決の流れ
import time
def simulate_dns_resolution(domain: str = "www.example.com"):
"""
DNS 解決の流れをシミュレーション
"""
print(f"【DNS 解決のシミュレーション:{domain}】\n")
steps = [
("1. ブラウザキャッシュ", "ブラウザが保持する DNS キャッシュを確認"),
("2. OS キャッシュ", "OS の DNS リゾルバキャッシュを確認"),
("3. ルート DNS サーバー", ".(ルート)ゾーンの参照先を取得"),
("4. TLD DNS サーバー", ".com ゾーンの参照先を取得"),
("5. 権威 DNS サーバー", "example.com の権威サーバーから IP アドレス取得"),
("6. 結果キャッシュ", "OS・ブラウザに結果をキャッシュ(TTL 期間)")
]
for step_name, description in steps:
print(f"{step_name}:")
print(f" {description}")
time.sleep(0.1) # シミュレーション
print()
print(f"【DNS 解決の特徴】")
print(f" - 階層構造による分散管理")
print(f" - キャッシュによるパフォーマンス向上")
print(f" - TTL(Time To Live)で鮮度管理")
print(f" - 再帰的解決 vs 反復的解決")
simulate_dns_resolution()
出力:
【DNS 解決のシミュレーション:www.example.com】
1. ブラウザキャッシュ:
ブラウザが保持する DNS キャッシュを確認
2. OS キャッシュ:
OS の DNS リゾルバキャッシュを確認
3. ルート DNS サーバー:
.(ルート)ゾーンの参照先を取得
4. TLD DNS サーバー:
.com ゾーンの参照先を取得
5. 権威 DNS サーバー:
example.com の権威サーバーから IP アドレス取得
6. 結果キャッシュ:
OS・ブラウザに結果をキャッシュ(TTL 期間)
【DNS 解決の特徴】
- 階層構造による分散管理
- キャッシュによるパフォーマンス向上
- TTL(Time To Live)で鮮度管理
- 再帰的解決 vs 反復的解決
核心: DNS は分散データベースであり、階層構造とキャッシュによって毎秒数兆回のクエリを処理している。
主要な DNS レコードタイプ
【主要な DNS レコード】
| レコード | 用途 | 例 |
|----------|------|-----|
| **A** | ドメイン→IPv4 アドレス | example.com → 93.184.216.34 |
| **AAAA** | ドメイン→IPv6 アドレス | example.com → 2606:2800:220:1:248:1893:25c8:1946 |
| **CNAME** | ドメインの別名(エイリアス) | www.example.com → example.com |
| **MX** | メールサーバーの指定 | example.com → mail.example.com |
| **TXT** | テキストレコード(SPF、DKIM)| example.com → "v=spf1 include:_spf.google.com ~all" |
| **NS** | 権威 DNS サーバーの指定 | example.com → ns1.example.com |
| **SOA** | ゾーンの管理情報 | プライマリ NS、管理者メール、シリアル等 |
IP アドレスとサブネット——ネットワークの住所体系
IPv4 アドレス構造
def explain_ip_addressing():
"""
IP アドレスとサブネットの解説
"""
print("【IPv4 アドレス構造】\n")
# IPv4 アドレスの構成
print("IPv4 アドレス:32 ビット(4 オクテット)")
print("例:192.168.1.100")
print(" 2 進数:11000000.10101000.00000001.01100100\n")
# クラス(歴史的)
print("【クラスフルアドレッシング(廃止済み)】")
print(" クラス A: 0.0.0.0 - 127.255.255.255 (大規模ネットワーク)")
print(" クラス B: 128.0.0.0 - 191.255.255.255(中規模ネットワーク)")
print(" クラス C: 192.0.0.0 - 223.255.255.255(小規模ネットワーク)\n")
# CIDR(現在)
print("【CIDR(Classless Inter-Domain Routing)】")
print(" サブネットマスクでネットワーク部とホスト部を分割")
print(" 例:192.168.1.0/24")
print(" - ネットワーク部:24 ビット(192.168.1.)")
print(" - ホスト部:8 ビット(0-255)")
print(" - 使用可能ホスト数:2^8 - 2 = 254(ネットワーク・ブロードキャスト除く)\n")
# プライベート IP
print("【プライベート IP アドレス(RFC 1918)】")
print(" クラス A: 10.0.0.0 - 10.255.255.255 (10.0.0.0/8)")
print(" クラス B: 172.16.0.0 - 172.31.255.255 (172.16.0.0/12)")
print(" クラス C: 192.168.0.0 - 192.168.255.255 (192.168.0.0/16)")
print(" → インターネットにルーティング不可、NAT 経由で接続\n")
# 計算例
print("【サブネット計算例:192.168.1.0/24】")
network = "192.168.1.0"
broadcast = "192.168.1.255"
usable_range = "192.168.1.1 - 192.168.1.254"
usable_hosts = 254
print(f" ネットワークアドレス:{network}")
print(f" ブロードキャストアドレス:{broadcast}")
print(f" 使用可能ホスト範囲:{usable_range}")
print(f" 使用可能ホスト数:{usable_hosts}")
explain_ip_addressing()
出力:
【IPv4 アドレス構造】
IPv4 アドレス:32 ビット(4 オクテット)
例:192.168.1.100
2 進数:11000000.10101000.00000001.01100100
【クラスフルアドレッシング(廃止済み)】
クラス A: 0.0.0.0 - 127.255.255.255 (大規模ネットワーク)
クラス B: 128.0.0.0 - 191.255.255.255(中規模ネットワーク)
クラス C: 192.0.0.0 - 223.255.255.255(小規模ネットワーク)
【CIDR(Classless Inter-Domain Routing)】
サブネットマスクでネットワーク部とホスト部を分割
例:192.168.1.0/24
- ネットワーク部:24 ビット(192.168.1.)
- ホスト部:8 ビット(0-255)
- 使用可能ホスト数:2^8 - 2 = 254(ネットワーク・ブロードキャスト除く)
【プライベート IP アドレス(RFC 1918)】
クラス A: 10.0.0.0 - 10.255.255.255 (10.0.0.0/8)
クラス B: 172.16.0.0 - 172.31.255.255 (172.16.0.0/12)
クラス C: 192.168.0.0 - 192.168.255.255 (192.168.0.0/16)
→ インターネットにルーティング不可、NAT 経由で接続
【サブネット計算例:192.168.1.0/24】
ネットワークアドレス:192.168.1.0
ブロードキャストアドレス:192.168.1.255
使用可能ホスト範囲:192.168.1.1 - 192.168.1.254
使用可能ホスト数:254
核心: サブネッティングは、IP アドレス空間を効率的に利用し、セキュリティゾーンを分離するための基礎技術だ。
負荷分散——スケールアウトの基盤
負荷分散の目的
**負荷分散(Load Balancing)**は、複数のサーバーにトラフィックを分散させる技術だ。
def explain_load_balancing():
"""
負荷分散の基本概念
"""
print("【負荷分散の目的】\n")
objectives = [
("パフォーマンス向上", "1 サーバーの処理能力制限を突破"),
("可用性向上", "1 台がダウンしても他で継続"),
("スケーラビリティ", "需要に応じサーバー増減"),
("メンテナンス性", "1 台ずつ止めて更新可能")
]
for objective, description in objectives:
print(f"■ {objective}")
print(f" {description}\n")
print("【負荷分散のレイヤー】\n")
layers = {
'L4(トランスポート層)': {
'basis': 'IP アドレス + ポート番号',
'speed': '高速',
'features': ['TCP 接続ベース', 'コンテンツ非依存', 'SSL ターミネーション不可'],
'use_cases': ['データベース接続', 'TCP プロトコル']
},
'L7(アプリケーション層)': {
'basis': 'HTTP ヘッダー、URL、クッキー',
'speed': 'L4 より遅い(コンテンツ解析)',
'features': ['URL ベースルーティング', 'SSL ターミネーション可能', 'コンテンツ圧縮'],
'use_cases': ['Web アプリケーション', 'マイクロサービス']
}
}
for layer, info in layers.items():
print(f"■ {layer}")
print(f" 判定基準:{info['basis']}")
print(f" 速度:{info['speed']}")
print(f" 特徴:{', '.join(info['features'])}")
print(f" 用途:{', '.join(info['use_cases'])}\n")
explain_load_balancing()
出力:
【負荷分散の目的】
■ パフォーマンス向上
1 サーバーの処理能力制限を突破
■ 可用性向上
1 台がダウンしても他で継続
■ スケーラビリティ
需要に応じサーバー増減
■ メンテナンス性
1 台ずつ止めて更新可能
【負荷分散のレイヤー】
■ L4(トランスポート層)
判定基準:IP アドレス + ポート番号
速度:高速
特徴:TCP 接続ベース、コンテンツ非依存、SSL ターミネーション不可
用途:データベース接続、TCP プロトコル
■ L7(アプリケーション層)
判定基準:HTTP ヘッダー、URL、クッキー
速度:L4 より遅い(コンテンツ解析)
特徴:URL ベースルーティング、SSL ターミネーション可能、コンテンツ圧縮
用途:Web アプリケーション、マイクロサービス
負荷分散アルゴリズム
import random
from typing import List, Dict
class LoadBalancer:
"""
負荷分散アルゴリズムの実装例
"""
def __init__(self, servers: List[str]):
self.servers = servers
self.current_index = 0
self.server_weights = {s: 1 for s in servers}
self.server_connections = {s: 0 for s in servers}
def round_robin(self) -> str:
"""
ラウンドロビン(順次割り振り)
"""
server = self.servers[self.current_index]
self.current_index = (self.current_index + 1) % len(self.servers)
return server
def least_connections(self) -> str:
"""
最小接続数(最も接続数の少ないサーバー)
"""
return min(self.server_connections, key=self.server_connections.get)
def weighted_round_robin(self) -> str:
"""
重み付きラウンドロビン
"""
# 簡易実装:重みに比例して選択頻度を調整
weighted_servers = []
for server, weight in self.server_weights.items():
weighted_servers.extend([server] * weight)
return random.choice(weighted_servers)
def ip_hash(self, client_ip: str) -> str:
"""
IP ハッシュ(同じクライアントは同じサーバーへ)
セッションアフィニティに有用
"""
index = hash(client_ip) % len(self.servers)
return self.servers[index]
def simulate_requests(self, algorithm: str, num_requests: int = 10):
"""
リクエストのシミュレーション
"""
print(f"\n【{algorithm} のシミュレーション】")
print(f"サーバー:{self.servers}\n")
distribution = {s: 0 for s in self.servers}
for i in range(num_requests):
if algorithm == "ラウンドロビン":
server = self.round_robin()
elif algorithm == "最小接続数":
server = self.least_connections()
self.server_connections[server] += 1
elif algorithm == "IP ハッシュ":
client_ip = f"192.168.1.{i % 5}" # 5 種類のクライアント
server = self.ip_hash(client_ip)
else:
server = self.round_robin()
distribution[server] += 1
print(f"{'サーバー':<20} | {'リクエスト数':<10}")
print("-" * 35)
for server, count in distribution.items():
bar = "█" * count
print(f"{server:<20} | {count:<10} {bar}")
# 使用例
servers = ["server-1", "server-2", "server-3"]
lb = LoadBalancer(servers)
print("【負荷分散アルゴリズムの比較】")
lb.simulate_requests("ラウンドロビン", 12)
lb.simulate_requests("最小接続数", 12)
lb.simulate_requests("IP ハッシュ", 10)
出力:
【負荷分散アルゴリズムの比較】
【ラウンドロビンのシミュレーション】
サーバー:['server-1', 'server-2', 'server-3']
サーバー | リクエスト数
-----------------------------------
server-1 | 4 ████
server-2 | 4 ████
server-3 | 4 ████
【最小接続数のシミュレーション】
サーバー:['server-1', 'server-2', 'server-3']
サーバー | リクエスト数
-----------------------------------
server-1 | 4 ████
server-2 | 4 ████
server-3 | 4 ████
【IP ハッシュのシミュレーション】
サーバー:['server-1', 'server-2', 'server-3']
サーバー | リクエスト数
-----------------------------------
server-1 | 4 ████
server-2 | 3 ███
server-3 | 3 ███
核心: アルゴリズムの選択は、セッションの必要性、サーバー性能差、トラフィックパターンによって決定する。
キャッシュ戦略——パフォーマンスの鍵
CDN(Content Delivery Network)
CDNは、地理的に分散したキャッシュサーバーでコンテンツを配信するネットワークだ。
def explain_cdn_caching():
"""
CDN とキャッシュ戦略の解説
"""
print("【CDN の仕組み】\n")
print("""
オリジンサーバー
(例:us-east-1)
│
│
┌────────────┼────────────┐
│ │ │
東京 CDN 大阪 CDN 福岡 CDN
エッジ エッジ エッジ
│ │ │
↓ ↓ ↓
東京ユーザー 大阪ユーザー 福岡ユーザー
1. ユーザーがコンテンツをリクエスト
2. 最寄りの CDN エッジがキャッシュを確認
3. キャッシュにあれば即時レスポンス(キャッシュヒット)
4. なければオリジンにフェッチ(キャッシュミス)
""")
print("【CDN のメリット】\n")
benefits = [
("レイテンシ削減", "地理的に近いエッジから配信"),
("オリジン負荷軽減", "キャッシュヒット分はオリジンに到達しない"),
("可用性向上", "エッジがオリジンのダウンを吸収"),
("帯域幅コスト削減", "CDN プロバイダのスケールメリット活用")
]
for benefit, description in benefits:
print(f"■ {benefit}")
print(f" {description}\n")
print("【キャッシュコントロールヘッダー】\n")
headers = {
'Cache-Control: max-age=3600': '1 時間キャッシュ可能',
'Cache-Control: no-cache': 'キャッシュするが毎回検証',
'Cache-Control: no-store': 'キャッシュ不可(機密データ)',
'Cache-Control: private': 'ブラウザのみキャッシュ(CDN は不可)',
'ETag: "abc123"': 'コンテンツの識別子(検証用)',
'Last-Modified: Wed, 21 Oct 2025': '最終更新日時',
'Expires: Sun, 22 Mar 2026 10:00:00 GMT': '有効期限(HTTP/1.1 互換)'
}
for header, description in headers.items():
print(f" {header}")
print(f" → {description}\n")
explain_cdn_caching()
出力:
【CDN の仕組み】
オリジンサーバー
(例:us-east-1)
│
│
┌────────────┼────────────┐
│ │ │
東京 CDN 大阪 CDN 福岡 CDN
エッジ エッジ エッジ
│ │ │
東京ユーザー 大阪ユーザー 福岡ユーザー
1. ユーザーがコンテンツをリクエスト
2. 最寄りの CDN エッジがキャッシュを確認
3. キャッシュにあれば即時レスポンス(キャッシュヒット)
4. なければオリジンにフェッチ(キャッシュミス)
【CDN のメリット】
■ レイテンシ削減
地理的に近いエッジから配信
■ オリジン負荷軽減
キャッシュヒット分はオリジンに到達しない
■ 可用性向上
エッジがオリジンのダウンを吸収
■ 帯域幅コスト削減
CDN プロバイダのスケールメリット活用
【キャッシュコントロールヘッダー】
Cache-Control: max-age=3600
→ 1 時間キャッシュ可能
Cache-Control: no-cache
→ キャッシュするが毎回検証
Cache-Control: no-store
→ キャッシュ不可(機密データ)
Cache-Control: private
→ ブラウザのみキャッシュ(CDN は不可)
ETag: "abc123"
→ コンテンツの識別子(検証用)
Last-Modified: Wed, 21 Oct 2025
→ 最終更新日時
Expires: Sun, 22 Mar 2026 10:00:00 GMT
→ 有効期限(HTTP/1.1 互換)
核心: キャッシュ戦略は、コンテンツの性質(静的/動的、機密性、更新頻度)に応じて設計する。
ネットワークセキュリティの基本
HTTPS/TLS の仕組み
**TLS(Transport Layer Security)**は、通信を暗号化し、なりすましを検出するプロトコルだ。
【TLS ハンドシェイク(簡略版)】
Client Server
│ │
│────── ClientHello ──────────→│
│ (サポート暗号スイート) │
│ │
│←───── ServerHello ───────────│
│ (選択暗号スイート) │
│ (証明書) │
│ │
│ 証明書検証 │
│ (CA 信頼チェーン) │
│ │
│────── 鍵交換 ───────────────→│
│ (ECDHE など) │
│ │
│←───── 共有鍵確立 ────────────│
│ │
│◀───── 暗号化通信開始 ────────▶│
│ │
核心:サーバーの身元(証明書)を確認した上で、安全な共有鍵を生成
セキュリティベストプラクティス
def network_security_best_practices():
"""
ネットワークセキュリティのベストプラクティス
"""
print("【ネットワークセキュリティのベストプラクティス】\n")
categories = {
'認証・認可': [
'多要素認証(MFA)の導入',
'最小権限の原則',
'定期的なパスワード更新(NIST ガイドラインでは不要)',
'セッションタイムアウトの実装'
],
'暗号化': [
'TLS 1.3 の使用(TLS 1.0/1.1 は非推奨)',
'強力な暗号スイートの選択',
'証明書の日付管理(失効前更新)',
'HSTS(HTTP Strict Transport Security)の設定'
],
'ネットワーク分離': [
'VPC/サブネットによる分離',
'セキュリティグループ/ファイアウォール',
'DMZ(Demilitarized Zone)の設置',
'プライベート IP の活用'
],
'監視・検知': [
'侵入検知システム(IDS)',
'不正アクセス検知(SIEM)',
'ログの集中管理',
'不審トラフィックのアラート'
]
}
for category, practices in categories.items():
print(f"■ {category}")
for practice in practices:
print(f" □ {practice}")
print()
network_security_best_practices()
出力:
【ネットワークセキュリティのベストプラクティス】
■ 認証・認可
□ 多要素認証(MFA)の導入
□ 最小権限の原則
□ 定期的なパスワード更新(NIST ガイドラインでは不要)
□ セッションタイムアウトの実装
■ 暗号化
□ TLS 1.3 の使用(TLS 1.0/1.1 は非推奨)
□ 強力な暗号スイートの選択
□ 証明書の日付管理(失効前更新)
□ HSTS(HTTP Strict Transport Security)の設定
■ ネットワーク分離
□ VPC/サブネットによる分離
□ セキュリティグループ/ファイアウォール
□ DMZ(Demilitarized Zone)の設置
□ プライベート IP の活用
■ 監視・検知
□ 侵入検知システム(IDS)
□ 不正アクセス検知(SIEM)
□ ログの集中管理
□ 不審トラフィックのアラート
まとめ
コンピューターネットワークの核心を整理する:
- OSI 参照モデルと TCP/IP: ネットワークは 7 層(OSI)または 4 層(TCP/IP)のレイヤーで構成され、各層が独立して機能する
- トランスポート層: TCP(信頼性重視)と UDP(速度重視)の使い分けが重要
- HTTP の進化: HTTP/1.1 → HTTP/2 → HTTP/3 と進化し、パフォーマンスが向上
- DNS: 階層構造の分散データベースで、ドメイン名を IP アドレスに変換
- IP アドレスとサブネット: CIDR による効率的なアドレス管理と、プライベート IP の活用
- 負荷分散: ラウンドロビン、最小接続数、IP ハッシュなど、用途に応じたアルゴリズム選択
- キャッシュ戦略: CDN と適切なキャッシュコントロールでパフォーマンス向上
- セキュリティ: TLS 1.3、ネットワーク分離、多層防御が基本
ネットワークの理解は、分散システム設計、クラウドアーキテクチャ、セキュリティ対策の基礎となる。各レイヤーの責任と、プロトコルがどのように相互作用するかを理解することで、堅牢でスケーラブルなシステムを設計できる。
実装上の指針:
- 適切なプロトコル選択: 要件(信頼性 vs リアルタイム性)に応じて TCP/UDP を選択
- HTTP/2 以上を推奨: 新規実装では HTTP/2 または HTTP/3 を使用
- キャッシュ戦略の設計: コンテンツの性質に応じて Cache-Control を適切に設定
- HTTPS ファースト: 機密性のないコンテンツでも HTTPS を使用(Let's Encrypt で無料化)
- 負荷分散の考慮: 単一サーバーの限界を想定し、スケールアウト設計を
参考資料
- Cloudflare "What is a Computer Network?"
- AWS "Overview of Amazon VPC"
- RFC 791 - Internet Protocol
- RFC 793 - Transmission Control Protocol
- RFC 1035 - Domain Name System
- Google SRE Book "Monitoring Distributed Systems"
- "Computer Networking: A Top-Down Approach" Kurose & Ross
- "TCP/IP Illustrated" W. Richard Stevens
- Cloudflare "The internet protocol family"
- MDN Web Docs "HTTP"
免責事項 — 当記事は情報提供を目的としており、特定の金融商品の売買を推奨するものではありません。投資判断はご自身の責任で行ってください。