今日のゴール
- 分散タプルスペースの概念を理解する
- クラスタノードの作成方法を学ぶ
- 分散環境での操作を体験する
分散タプルスペースとは
複数のマシンにまたがるタプルスペースです。
なぜ分散が必要か
| 課題 | 分散による解決 |
|---|---|
| スケーラビリティ | 複数ノードでデータを分担 |
| 可用性 | 一部障害でもサービス継続 |
| 地理的分散 | ユーザーに近いノードで処理 |
| 耐障害性 | データの冗長化 |
ClusterNodeの作成
import ninda/distributed/cluster
# ノードを作成
let node = newClusterNode(
nodeId = "node-1",
host = "127.0.0.1",
port = 9000
)
# ピアを追加
node.addPeer("node-2", "127.0.0.1", 9001)
node.addPeer("node-3", "127.0.0.1", 9002)
# 分散操作
await node.write(toTuple(strVal("distributed"), intVal(42)))
let result = await node.read(toPattern(strVal("distributed"), nilValue()))
ノード構成のポイント
| 設定 | 説明 |
|---|---|
| nodeId | クラスタ内で一意な識別子 |
| host | 他ノードからアクセス可能なアドレス |
| port | 通信ポート |
| peers | 接続先ノードのリスト |
一貫性モデル
Nindaは2つの一貫性モデルを提供します:
| モデル | 特徴 | 用途 |
|---|---|---|
| 結果整合性(CRDT) | 低遅延、高可用性、競合自動解決 | 一般的なワークロード |
| 強整合性(Raft) | 一貫性保証、過半数必要 | クリティカルなデータ |
ノードステータス
ノードの状態はGossipプロトコルで追跡されます:
| 状態 | 説明 |
|---|---|
| Unknown | 初期状態、まだ通信なし |
| Alive | 正常動作中 |
| Suspect | 応答遅延、障害の可能性 |
| Dead | 障害と判断、クラスタから除外 |
分散操作の流れ
ポイント:
- クライアントはローカルノードに書き込み
- バックグラウンドで他ノードに伝播
- 最終的にすべてのノードで一致
まとめ
学んだこと
| トピック | ポイント |
|---|---|
| ClusterNode | 分散ノードの構成単位 |
| Peer管理 | ノード間の接続 |
| 一貫性モデル | 結果整合性と強整合性 |
| ノードステータス | Gossipによる状態追跡 |
いつ使うか
| 場面 | 推奨 |
|---|---|
| 単一マシン | SpaceManager(分散なし) |
| スケーラビリティ必要 | ClusterNode |
| 高可用性必要 | ClusterNode + 複数ノード |
| 地理分散 | ClusterNode + 各拠点にノード |
演習問題
問題17-1: ローカルクラスタ
3つのノード(ポート9000, 9001, 9002)でローカルクラスタを構成し、1つのノードに書き込んだタプルが他のノードから読めることを確認してください。
ヒント
- 3つのターミナルで3つのノードを起動
- 各ノードは他の2ノードをpeerとして追加
- Node 1で
write、Node 2でread - 伝播に少し時間がかかるので
sleepAsyncで待機
問題17-2: ノード障害テスト
3ノードクラスタで1つのノードを停止し、残り2ノードでサービスが継続することを確認してください。
ヒント
- Node 3を
Ctrl+Cで停止 - Node 1とNode 2で引き続き
write/readが動作するか確認 - しばらくするとNode 3のステータスが
Suspect→Deadに変化 - Node 3を再起動すると再び
Aliveになる
問題17-3: 自動ピア検出
新しいノードが参加したときに自動的にピアリストに追加される仕組みを考えてください(設計のみ)。
ヒント
- 既存ノードのピアリストをGossipで伝播
- 新ノードは1つのノードに接続すれば全ノードを知れる
- 「ノード参加」イベントを全ノードに伝播
- ブートストラップノードのアドレスは設定で指定
前回: 永続化とWAL | 目次 | 次回: CRDT入門