Skip to content
Published on

[オペレーティングシステム] 19. ネットワークと分散システム

Authors

ネットワークと分散システム

現代のコンピューティング環境は、ネットワークで接続された複数のコンピュータが協力して動作します。この記事では、ネットワークの基礎、分散システムの概念と課題、分散ファイルシステム、MapReduce、そして分散調整メカニズムを解説します。


1. ネットワーク種類

┌───────────────────────────────────────────────┐
│          ネットワーク規模別分類                 │
│                                               │
PAN (Personal Area Network):│  ┌───────────────────┐                        │
│  │ Bluetooth, NFC     │  ~数メートル          │
│  └───────────────────┘                        │
│                                               │
LAN (Local Area Network):│  ┌───────────────────┐                        │
│  │ Ethernet, Wi-Fi   │  建物/キャンパス内     │
│  │ 1~10 Gbps         │                        │
│  └───────────────────┘                        │
│                                               │
MAN (Metropolitan Area Network):│  ┌───────────────────┐                        │
│  │ 都市規模ネットワーク│                       │
│  └───────────────────┘                        │
│                                               │
WAN (Wide Area Network):│  ┌───────────────────┐                        │
│  │ 国家/大陸間接続    │  インターネット        │
│  └───────────────────┘                        │
└───────────────────────────────────────────────┘

2. TCP/IPモデル

┌─────────────────────────────────────────────┐
TCP/IP 4階層モデル                  │
│                                             │
│  ┌─────────────────┐                        │
│  │ アプリケーション │  HTTP, FTP, DNS, SSH│  │ 層              │  ソケットAPI│  ├─────────────────┤                        │
│  │ トランスポート層 │  TCP(信頼性、順序)    │
│  │                 │  UDP(高速、コネクションレス)│
│  ├─────────────────┤                        │
│  │ インターネット層 │  IP(アドレス、ルーティング)│
│  │                 │  ICMP, ARP│  ├─────────────────┤                        │
│  │ リンク層        │  Ethernet, Wi-Fi│  │                 │  MACアドレス           │
│  └─────────────────┘                        │
└─────────────────────────────────────────────┘

TCP vs UDP

特性TCPUDP
接続コネクション型(3ウェイ)コネクションレス
信頼性保証(再送、順序保証)保証なし
速度相対的に遅い高速
用途Web、メール、ファイル転送ストリーミング、DNS、ゲーム

ソケットプログラミングの例

// TCP 서버 예시 (C)
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    char buffer[1024];

    server_fd = socket(AF_INET, SOCK_STREAM, 0);

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8080);
    bind(server_fd, (struct sockaddr *)&server_addr,
         sizeof(server_addr));

    listen(server_fd, 5);
    printf("서버 대기 중 (포트 8080)...\n");

    client_fd = accept(server_fd,
                       (struct sockaddr *)&client_addr,
                       &client_len);

    int bytes = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
    buffer[bytes] = '\0';
    printf("수신: %s\n", buffer);

    const char *response = "Hello from server!";
    send(client_fd, response, strlen(response), 0);

    close(client_fd);
    close(server_fd);
    return 0;
}
// TCP 클라이언트 예시 (C)
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

int main() {
    int sock;
    struct sockaddr_in server_addr;
    char buffer[1024];

    sock = socket(AF_INET, SOCK_STREAM, 0);

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);
    connect(sock, (struct sockaddr *)&server_addr,
            sizeof(server_addr));

    const char *message = "Hello from client!";
    send(sock, message, strlen(message), 0);

    int bytes = recv(sock, buffer, sizeof(buffer) - 1, 0);
    buffer[bytes] = '\0';
    printf("서버 응답: %s\n", buffer);

    close(sock);
    return 0;
}

3. 分散システム

複数の独立したコンピュータがネットワークを通じて協力し、1つのシステムのように動作します。

利点と課題

利点:                              課題:
┌──────────────────────────┐      ┌──────────────────────────┐
│ リソース共有              │      │ ネットワーク障害          │
- ストレージ、演算リソース│      │ - 部分障害処理            │
│                          │      │                          │
│ スケーラビリティ          │      │ 一貫性維持               │
- 水平拡張(ノード追加) │      │ - データ複製時の一貫性   │
│                          │      │                          │
│ 可用性                   │      │ セキュリティ             │
- ノード障害時の自動復旧 │      │ - ネットワーク通信の安全 │
│                          │      │                          │
│ 性能                     │      │ 時計同期                 │
- 並列処理でスループット向上│    │ - 分散環境のイベント順序 │
└──────────────────────────┘      └──────────────────────────┘

CAP定理

分散システムは一貫性(Consistency)、可用性(Availability)、分断耐性(Partition Tolerance)の3つを同時に満たすことができません。

        一貫性 (C)
        ╱       ╲
CA       (単一サーバー)     ╱               ╲
    ╱                  ╲
可用性 (A) ──── 分断耐性 (P)
         AP / CP

ネットワーク分断は不可避なため:
- CPシステム: 一貫性優先 (: ZooKeeper, HBase)
  → 分断時に一部リクエスト拒否
- APシステム: 可用性優先 (: Cassandra, DynamoDB)
  → 分断時に不一致許容、後で収束

4. 分散ファイルシステム

NFS(Network File System)

クライアントA ──→ ┐
クライアントB ──→ ├→ NFSサーバー ──→ ローカルディスク
クライアントC ──→ ┘

特徴:
- リモートファイルをローカルのようにアクセス(透過性)
- POSIX互換インターフェース
- クライアント側キャッシングで性能向上

GFS(Google File System)

大容量ファイルのための分散ファイルシステムです。

┌──────────────────────────────────────────┐
GFS アーキテクチャ              │
│                                          │
│  ┌───────────────┐                       │
│  │  GFS Master   │  ← メタデータ管理     │
  (Name Node)    (ファイル→チャンクマッピング)│  └───────┬───────┘                       │
│  ┌───────┼───────┬───────┐               │
│  ▼       ▼       ▼       ▼               │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐             │
│ │Chunk│ │Chunk│ │Chunk│ │Chunk│           │
│ │Srv 1│ │Srv 2│ │Srv 3│ │Srv 4│           │
│ └────┘ └────┘ └────┘ └────┘             │
│                                          │
│ ファイル → 64MBチャンクに分割            │
│ 各チャンクは3台のサーバーに複製(耐障害性)│
└──────────────────────────────────────────┘

HDFS(Hadoop Distributed File System)

GFSのオープンソース実装で、大規模データ処理に最適化されています。

┌─────────────────────────────────────────┐
HDFS アーキテクチャ            │
│                                         │
│  ┌────────────┐                         │
│  │ NameNode   │ ← メタデータ(メモリ)  │
│  │            │   ファイル名→ブロック    │
│  │            │   ブロック→DataNode      │
│  └─────┬──────┘                         │
│        │ Heartbeat + Block Report│  ┌─────┼──────┬──────────┐              │
│  ▼     ▼      ▼          ▼              │
│ ┌────┐┌────┐┌────┐    ┌────┐            │
│ │DN 1││DN 2││DN 3│    │DN 4│            │
│ │Blk1││Blk1││Blk2│    │Blk2│            │
│ │Blk3││Blk2││Blk3│    │Blk1│            │
│ └────┘└────┘└────┘    └────┘            │
│                                         │
│ デフォルトブロックサイズ: 128MB          │
│ 複製係数: 3(デフォルト)                │
└─────────────────────────────────────────┘
// HDFS Java API 예시
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FSDataInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class HdfsExample {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(conf);

        Path writePath = new Path("/user/data/output.txt");
        FSDataOutputStream out = fs.create(writePath);
        out.writeUTF("Hello, HDFS!");
        out.close();

        Path readPath = new Path("/user/data/output.txt");
        FSDataInputStream in = fs.open(readPath);
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(in)
        );
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        reader.close();

        fs.delete(new Path("/user/data/output.txt"), false);
        fs.close();
    }
}

5. MapReduce

大規模データを並列処理するプログラミングモデルです。

入力データ(3分割):

Split 1: "hello world hello"
Split 2: "world foo hello"
Split 3: "bar foo hello"

     │           │           │
     ▼           ▼           ▼
  ┌──────┐   ┌──────┐   ┌──────┐
Map 1 │   │Map 2 │   │Map 3 │   ← Mapフェーズ
  └──┬───┘   └──┬───┘   └──┬───┘
  (hello,1)   (world,1)   (bar,1)
  (world,1)   (foo,1)     (foo,1)
  (hello,1)   (hello,1)   (hello,1)
     │           │           │
     └─────┬─────┘───────────┘
     Shuffle & Sort(キー別グループ化)
  ┌────────┴────────────────────────┐
  │ bar:    [1]  │ foo:    [1, 1]  │ hello:  [1, 1, 1, 1]  │ world:  [1, 1]  └────────┬────────────────────────┘
     ┌─────┴──────┐
     ▼            ▼
  ┌──────┐   ┌──────┐
  │Red. 1│   │Red. 2│   ← Reduceフェーズ
  └──┬───┘   └──┬───┘
  bar:1       hello:4
  foo:2       world:2
// WordCount MapReduce 예시 (Java)
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import java.io.IOException;

public class WordCountMapper
    extends Mapper<Object, Text, Text, IntWritable> {

    private final static IntWritable one = new IntWritable(1);
    private Text word = new Text();

    public void map(Object key, Text value, Context context)
        throws IOException, InterruptedException {
        String[] words = value.toString().split("\\s+");
        for (String w : words) {
            word.set(w);
            context.write(word, one);
        }
    }
}

public class WordCountReducer
    extends Reducer<Text, IntWritable, Text, IntWritable> {

    public void reduce(Text key, Iterable<IntWritable> values,
                       Context context)
        throws IOException, InterruptedException {
        int sum = 0;
        for (IntWritable val : values) {
            sum += val.get();
        }
        context.write(key, new IntWritable(sum));
    }
}

6. クラウドストレージ

クラウド環境で大規模データを保存・管理するサービスです。

┌────────────────────────────────────────────────┐
│       クラウドストレージサービス比較             │
│                                                │
AWS:│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐          │
│  │ S3   │ │ EBS  │ │ EFS  │ │Glacier│         │
│  │オブジェクト│ │ブロック│ │ファイル│ │アーカイブ│ │
│  └──────┘ └──────┘ └──────┘ └──────┘          │
│                                                │
│  ストレージクラス(S3基準):StandardIAGlacierDeep Archive  (ホット)  (ウォーム)(コールド)(アーカイブ)│  アクセス頻度高 ──────→ アクセス頻度低          │
│  コスト高 ────────────→ コスト低               │
└────────────────────────────────────────────────┘

7. 分散調整(Distributed Coordination)

合意アルゴリズム - Raft

分散システムでノードが同じ状態に合意するアルゴリズムです。

Raftリーダー選出:

Node A (Follower)  Node B (Leader)  Node C (Follower)
    │                   │                │
    │  ←── Heartbeat ── │ ── Heartbeat → │
    │                   │                │
X(障害発生)    │
    │  (タイムアウト)  │                │
    │  → Candidate!     │                │
    │ ── RequestVote ────────────────→   │
    │ ←──────────────── Vote ────────   │
    │  → 新しいLeader!    │ ── AppendEntries (Heartbeat) ──→   │

ZooKeeper

分散アプリケーションのための調整サービスです。

┌──────────────────────────────────────┐
ZooKeeper アンサンブル         │
│                                      │
│  ┌────────┐ ┌────────┐ ┌────────┐   │
│  │Server 1│ │Server 2│ │Server 3│   │
(Leader)(Follow.)(Follow.)│  │
│  └────────┘ └────────┘ └────────┘   │
│                                      │
ZNodeツリー構造:/│  ├── /config                         │
│  │   ├── /config/database            │
│  │   └── /config/cache               │
│  ├── /locks                          │
│  │   └── /locks/resource1            │
│  └── /members                        │
│      ├── /members/node1              │
│      └── /members/node2              │
└──────────────────────────────────────┘
// ZooKeeper 분산 잠금 예시 (Java, 의사 코드)
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;

public class DistributedLock {
    private ZooKeeper zk;
    private String lockPath;

    public DistributedLock(ZooKeeper zk, String resource) {
        this.zk = zk;
        this.lockPath = "/locks/" + resource;
    }

    public void lock() throws Exception {
        String myNode = zk.create(
            lockPath + "/lock-",
            new byte[0],
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL
        );

        while (true) {
            var children = zk.getChildren(lockPath, false);
            String smallest = children.stream()
                .sorted().findFirst().orElse(null);
            if (myNode.endsWith(smallest)) {
                return;
            }
            Thread.sleep(100);
        }
    }

    public void unlock() throws Exception {
        zk.delete(lockPath, -1);
    }
}

8. まとめ

  • ネットワーク: TCP/IP 4階層モデル、TCP(信頼性)vs UDP(高速)
  • 分散システム: リソース共有とスケーラビリティの利点、CAP定理のトレードオフ
  • 分散ファイルシステム: NFS(従来型)、GFS/HDFS(大規模データ)
  • MapReduce: Map(分散処理)+ Reduce(集約)で並列データ処理
  • クラウドストレージ: オブジェクト/ブロック/ファイルストレージ、ティアリングでコスト最適化
  • 分散調整: Raft合意アルゴリズム、ZooKeeper調整サービス
クイズ:ネットワークと分散システム

Q1. CAP定理におけるCPシステムとAPシステムの違いは?

A1. CPシステム(例:ZooKeeper)はネットワーク分断時に一貫性を維持するために一部リクエストを拒否し可用性を犠牲にします。APシステム(例:Cassandra)はネットワーク分断時でもすべてのリクエストに応答しますが、ノード間データが一時的に不一致になる可能性があり、後で収束(eventual consistency)します。

Q2. HDFSでデータブロックを3つ複製する理由は?

A2. 3つの複製は耐障害性と性能のバランスを提供します。1台のDataNodeが障害を起こしても残り2つの複製からデータを読めます。また読み取りリクエストを複数の複製に分散してスループットを向上できます。HDFSは複製を異なるラックに配置してラックレベルの障害にも備えます。

Q3. MapReduceにおけるShuffleフェーズの役割は?

A3. ShuffleフェーズはMapの出力をキー(key)別にソート・グループ化して、同じキーを持つすべての値を1つのReducerに渡します。この過程でネットワークを通じたデータ転送が発生するため、MapReduceで最もコストの大きいフェーズであり、パフォーマンス最適化の核心対象です。