photoncloud-monorepo/chainfire/advice.md
centra 8f94aee1fa Fix R8: Convert submodule gitlinks to regular directories
- Remove gitlinks (160000 mode) for chainfire, flaredb, iam
- Add workspace contents as regular tracked files
- Update flake.nix to use simple paths instead of builtins.fetchGit

This resolves the nix build failure where submodule directories
appeared empty in the nix store.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 16:51:20 +09:00

87 lines
6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

RaftとGossipプロトコルを用いた、クラスター管理のための数万台までスケールするKey-Value Storeを書いてほしいです。
- プログラミング言語rust
- テストをちゃんと書きながら書くことを推奨する。
- クラスターへの参加/削除/障害検知を行う。
では、**「Raft合意形成」と「Gossip情報の拡散」を組み合わせた場合、具体的にどうデータが流れ、どうやってードが動き出すのか**、その具体的なフローを解説します。
-----
### 前提:このシステムの役割分担
* **Control Plane (CP):** Raftで構成された3〜7台Raftアルゴリズムでうまく合意が取れる範囲のサーバー。情報の「正規の持ち主」。いなくなったら自動でWorker Nodesから昇格する。
* **Worker Nodes (VM/DB Hosts):** 数百〜数千台の実働部隊。CPのクライアント。
### 1\. データはどのように書き込まれるか? (Write)
書き込みは **「必ず Control Plane の Raft Leader に対して」** 行います。Gossip経由での書き込みは順序保証がないため行いません。
「VM-A を Node-10 で起動したい」
1. **API Call:** 管理者またはCLIが、CPのAPIサーバーにリクエストを送ります。
2. **Raft Log:** CPのリーダーは、この変更を `Put(Key="/nodes/node-10/tasks/vm-a", Value="START")` としてRaftログに追加します。
3. **Commit:** 過半数のCPードがログを保存したら「書き込み完了」と見なします。
ここまでは普通のDBと同じです。
### 2\. 各ノードはどのようにデータを取得し、通知を受けるか? (Read & Notify)
ここが最大のポイントです。数千台のードが「自分宛ての命令はないか」と毎秒ポーリング問い合わせすると、CPがDDoS攻撃を受けたようにパンクします。
ここで **「Watchロングポーリング」** という仕組みを使います。
#### A. Watchによる通知と取得これがメイン
Kubernetesやetcdが採用している方式です。
1. **接続維持:** Node-10 は起動時に CP に対して `Watch("/nodes/node-10/")` というリクエストを送ります。
2. **待機:** CP は「Node-10 以下のキーに変更があるまで、レスポンスを返さずに接続を維持(ブロック)」します。
3. **イベント発火:** 先ほどの書き込みVM起動命令が発生した瞬間、CP は待機していた Node-10 への接続を通じて「更新イベントEvent: PUT, Key: ...vm-a, Value: START」を即座にプッシュします。
4. **アクション:** Node-10 は通知を受け取り次第、VMを起動します。
**結論:** 「書き込み後の通知」は絶対に必要です。それを効率よくやるのが **Watch API** です。
-----
### 3\. じゃあ Gossip はどこで使うのか?
「Raft + Watch」で完結しそうに見えますが、10台以上のスケール、特にVM基盤のような動的な環境では **Gossip が以下の「3つの穴」を埋めるために不可欠** になります。
#### ① Nodeの死活監視・インベントリ管理下り方向
CPが「Node-10にVMを立てたい」と思ったとき、「そもそもNode-10は生きているのか IPは 空きメモリは?」という情報を知る必要があります。
* **Gossipの役割:** 各Worker Nodeは、GossipSWIMプロトコルでお互いに、そしてCPに対して「自分は生きてるよ、IPはこれだよ」と喋り続けます。
* CPはこのGossip情報を聞いて、最新の「ード一覧リストMemberlist」をメモリ上に保持します。
#### ② サービスのディスカバリ(横方向)
DB基盤の場合、「DBードA」が「DBードB」と通信したいことがあります。いちいちCPに聞きに行くと遅いです。
* **Gossipの役割:** ード同士で「私はここにいるよ」とGossipし合うことで、CPを介さずに直接通信相手を見つけられます。
#### ③ "Actual State"(現状)の報告(上り方向)
VMが起動した後、「起動しました」というステータスをどうCPに伝えるか。
* **Raftに書く:** 確実ですが、頻繁に変わるステータスCPU使用率などを全部Raftに書くとCPがパンクします。
* **Gossipで流す:** 「VM-Aは起動中、負荷50%」といった情報はGossipに乗せて、**「結果的にCPに伝わればいい」** という扱いにします。
-----
### 設計のまとめRaftとGossipの使い分け
これから作る「汎用管理DB外部依存型」は、以下のようなインターフェースを持つことになるでしょう。
| アクション | 通信方式 | 具体的なデータ例 |
| :--- | :--- | :--- |
| **命令 (Desired State)**<br>「こうなってほしい」 | **Raft + Watch**<br>(強整合性) | ・VMの起動/停止命令<br>・DBのデータ配置情報の変更<br>・パスワードや設定変更 |
| **現状 (Actual State)**<br>「今こうなってます」 | **Gossip**<br>(結果整合性) | ・ノードの生存確認 (Heartbeat)<br>・リソース使用率 (CPU/Mem)<br>・「VM起動完了」などのステータス |
| **通知 (Notification)** | **Watch (HTTP/gRPC Stream)** | ・「新しい命令が来たぞ!」というトリガー |
#### 実装のアドバイス
もし「etcdのようなもの」を自作されるなら、**「Serf (Gossip)」と「Raft」をライブラリとして組み込み、その上に「gRPCによるWatch付きのKVS API」を被せる** という構成になります。
これができれば、VM基盤は「Watchして、VMを起動して、Gossipでステータスを返すエージェント」を作るだけで済みますし、DB基盤も同様に作れます。非常にスケーラブルで美しい設計です。