Files
microdao-daarion/DECENTRALIZED-NODE-ARCHITECTURE.md
Apple 3de3c8cb36 feat: Add presence heartbeat for Matrix online status
- matrix-gateway: POST /internal/matrix/presence/online endpoint
- usePresenceHeartbeat hook with activity tracking
- Auto away after 5 min inactivity
- Offline on page close/visibility change
- Integrated in MatrixChatRoom component
2025-11-27 00:19:40 -08:00

678 lines
20 KiB
Markdown
Raw Permalink 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.
# 🌐 Децентралізована мережа нод - Архітектура автоматичного підключення
**Дата:** 2025-11-23
**Версія:** 2.0.0
**Статус:** 🎯 Production Architecture
---
## 🎯 Мета
Створити повністю автоматизовану систему для додавання нових нод до децентралізованої мережі штучного інтелекту без ручного втручання.
---
## 🏗️ Архітектура мережі
### Поточна структура
```
┌─────────────────────────────────────────────────────────┐
│ DAARION AI Network │
├─────────────────────────────────────────────────────────┤
│ │
НОДА1 (Hetzner) ◄──────────────────┐ │
│ 144.76.224.179 │ │
│ ├─ Node Registry (9205) │ │
│ ├─ NATS JetStream (4222) │ │
│ ├─ DAGI Router (9102) │ Discovery │
│ └─ Gateway (9300) │ & Heartbeat │
│ │ │
НОДА2 (MacBook M4 Max) ─────────────┘ │
│ 192.168.1.33 (local) │
│ ├─ Development Node │
│ ├─ 50 DAARION Agents │
│ └─ 8 AI Models │
│ │
НОДА3-N (Future) ───────────────────┐ │
│ Any location │ │
│ └─ Auto-registration ────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
---
## 🔧 Компоненти системи
### 1. Node Registry Service (Вже існує!)
**Місце:** НОДА1 (144.76.224.179:9205)
**Статус:** ✅ Готовий (потрібна імплементація API)
**Призначення:**
- Центральний реєстр всіх нод
- Автоматична реєстрація нових нод
- Heartbeat tracking (keep-alive)
- Node discovery
**База даних:**
```sql
-- nodes table
node_id VARCHAR(255) -- Унікальний ID ноди
node_name VARCHAR(255) -- Людське ім'я
ip_address INET -- Публічна IP
local_ip INET -- Локальна IP
status VARCHAR(50) -- online, offline, degraded
last_heartbeat TIMESTAMP -- Останній heartbeat
capabilities JSONB -- GPU, CPU, RAM, моделі
```
**API Endpoints:**
```bash
POST /api/v1/nodes/register # Реєстрація нової ноди
POST /api/v1/nodes/heartbeat # Heartbeat (keep-alive)
GET /api/v1/nodes # Список всіх нод
GET /api/v1/nodes/{node_id} # Інфо про конкретну ноду
GET /api/v1/nodes/discover # Знайти ноди з певними capabilities
```
---
### 2. Bootstrap Agent (Авто-реєстрація)
**Файл:** `tools/dagi_node_agent/bootstrap.py`
**Статус:** ✅ Існує, потрібне покращення
**Як працює:**
```python
# Запуск на новій ноді
python3 -m tools.dagi_node_agent.bootstrap \
--role production-node \
--labels gpu,cpu,ollama \
--registry-url http://144.76.224.179:9205
```
**Що робить:**
1. ✅ Автоматично визначає hostname, IP
2. ✅ Генерує унікальний node_id
3. ✅ Збирає інформацію про систему (CPU, RAM, GPU)
4. ✅ Реєструється в Node Registry
5. ✅ Зберігає node_id локально
6. ✅ Запускає heartbeat loop
---
### 3. Heartbeat Service (Keep-Alive)
**Призначення:** Підтримувати з'єднання з Registry
**Механізм:**
```python
# Кожні 30 секунд відправляє heartbeat
while True:
await send_heartbeat(node_id, metrics)
await asyncio.sleep(30)
```
**Метрики що відправляються:**
- CPU usage %
- RAM usage %
- GPU usage % (якщо є)
- Disk usage %
- Активні сервіси
- Кількість агентів
- Статус моделей
---
### 4. Discovery Service (Пошук нод)
**Призначення:** Знайти ноду з потрібними capabilities
**API Query:**
```bash
# Знайти ноду з GPU
GET /api/v1/nodes/discover?capability=gpu&status=online
# Знайти ноду з конкретною моделлю
GET /api/v1/nodes/discover?model=deepseek-r1:70b
# Знайти найближчу ноду
GET /api/v1/nodes/discover?latency=min&region=europe
```
**Response:**
```json
{
"nodes": [
{
"node_id": "node-1-hetzner",
"ip_address": "144.76.224.179",
"latency_ms": 45,
"capabilities": {
"gpu": "NVIDIA RTX 4000",
"models": ["qwen3:8b", "mistral:7b"]
}
}
]
}
```
---
## 🚀 Автоматичне підключення нової ноди
### Сценарій: Додавання НОДА3
#### Крок 1: Встановлення на новій ноді
```bash
# На НОДА3
git clone git@github.com:IvanTytar/microdao-daarion.git
cd microdao-daarion
pip install -r requirements.txt
```
#### Крок 2: Конфігурація (один файл)
```bash
# Створити .env файл
cat > .env << EOF
# Node Registry URL
NODE_REGISTRY_URL=http://144.76.224.179:9205
# NATS для комунікації
NATS_URL=nats://144.76.224.179:4222
# Роль ноди
NODE_ROLE=worker-node
NODE_LABELS=gpu,inference,home
# Ollama (якщо є)
OLLAMA_BASE_URL=http://localhost:11434
EOF
```
#### Крок 3: Автоматична реєстрація
```bash
# Запустити bootstrap
python3 -m tools.dagi_node_agent.bootstrap --auto
```
**Що відбудеться автоматично:**
1. ✅ Визначить hostname та IP
2. ✅ Згенерує унікальний node_id
3. ✅ Зсканує систему (CPU, RAM, GPU, диск)
4. ✅ Перевірить наявність Ollama та моделей
5. ✅ Зареєструється в Node Registry
6. ✅ Запустить heartbeat service
7. ✅ Стане доступною в мережі через 30 секунд
#### Крок 4: Перевірка
```bash
# На будь-якій ноді
curl http://144.76.224.179:9205/api/v1/nodes
# Побачите НОДА3 в списку!
```
---
## 🔐 Безпека та автентифікація
### Рівень 1: API Key (Базовий)
```bash
# При реєстрації генерується API key
NODE_API_KEY=sk-node-abc123xyz
# Всі запити до Registry потребують ключ
curl -H "Authorization: Bearer $NODE_API_KEY" \
http://144.76.224.179:9205/api/v1/nodes
```
### Рівень 2: mTLS (Mutual TLS)
```bash
# Кожна нода має свій сертифікат
NODE_CERT=/etc/dagi/certs/node.crt
NODE_KEY=/etc/dagi/certs/node.key
CA_CERT=/etc/dagi/certs/ca.crt
# Всі з'єднання через TLS
```
### Рівень 3: Whitelist (IP або node_id)
```python
# В Node Registry
ALLOWED_NODES = [
"node-1-hetzner",
"node-2-macbook",
# Автоматично додаються після верифікації
]
```
---
## 🌍 Топології мережі
### Топологія 1: Централізована (поточна)
```
НОДА1 (Registry)
/ | \
/ | \
НОДА2 НОДА3 НОДА4
```
**Плюси:**
- ✅ Простота
- ✅ Один point of truth
- ✅ Легке управління
**Мінуси:**
- ⚠️ Single point of failure
- ⚠️ Bottleneck при великій кількості нод
### Топологія 2: Федеративна (майбутнє)
```
НОДА1 (Registry-EU) ◄────► НОДА5 (Registry-US)
/ | \ / | \
НОДА2 3 4 НОДА6 7 8
```
**Плюси:**
- ✅ Відмовостійкість
- ✅ Географічна близькість
- ✅ Масштабованість
**Мінуси:**
- ⚠️ Складніша синхронізація
- ⚠️ Eventual consistency
### Топологія 3: P2P (повна децентралізація)
```
НОДА1 ◄──► НОДА2
▲ \ / ▲
│ \ / │
│ ◄ │
└─► НОДА3 ◄─┘
```
**Плюси:**
- ✅ Повна децентралізація
- ✅ Максимальна відмовостійкість
- ✅ Немає central authority
**Мінуси:**
- ⚠️ Складна імплементація
- ⚠️ Consensus протоколи потрібні
---
## 📡 Протоколи комунікації
### 1. HTTP/REST (Реєстрація та discovery)
```
Використання: Реєстрація, heartbeat, queries
Протокол: HTTP/HTTPS
Порт: 9205
```
### 2. NATS JetStream (Messaging)
```
Використання: Асинхронні повідомлення, events
Протокол: NATS
Порт: 4222
Topics:
- node.{node_id}.events
- node.{node_id}.tasks
- system.broadcast
```
### 3. gRPC (High-performance calls)
```
Використання: Швидкі запити між нодами
Протокол: gRPC/HTTP2
Порт: 9106 (майбутнє)
```
### 4. WebSocket (Real-time)
```
Використання: Real-time dashboard, monitoring
Протокол: WebSocket
Порт: 9107 (майбутнє)
```
---
## 🔄 Життєвий цикл ноди
### 1. Registration (Реєстрація)
```
НОДА3 → POST /api/v1/nodes/register → Node Registry
Response: {node_id, api_key, config}
```
### 2. Active (Працює)
```
НОДА3 → POST /api/v1/nodes/heartbeat (every 30s) → Registry
Registry → Marks node as "online"
```
### 3. Degraded (Проблеми)
```
Heartbeat timeout > 90s
Registry → Marks node as "degraded"
Alert sent to admin
```
### 4. Offline (Відключена)
```
Heartbeat timeout > 5min
Registry → Marks node as "offline"
Node removed from active routing
```
### 5. Deregistration (Видалення)
```
НОДА3 → DELETE /api/v1/nodes/{node_id} → Registry
Registry → Removes node from database
```
---
## 🛠️ Практична імплементація
### Файл 1: `bootstrap.py` (Покращений)
```python
#!/usr/bin/env python3
"""
Автоматична реєстрація ноди в DAARION Network
"""
import socket
import platform
import psutil
import requests
import uuid
from pathlib import Path
class NodeBootstrap:
def __init__(self, registry_url):
self.registry_url = registry_url
self.node_id = self.generate_node_id()
def generate_node_id(self):
"""Генерує унікальний node_id"""
hostname = socket.gethostname()
# Якщо є збережений ID - використати його
node_id_file = Path.home() / ".dagi" / "node_id"
if node_id_file.exists():
return node_id_file.read_text().strip()
# Інакше створити новий
short_uuid = str(uuid.uuid4())[:8]
node_id = f"node-{hostname}-{short_uuid}"
# Зберегти для майбутнього використання
node_id_file.parent.mkdir(parents=True, exist_ok=True)
node_id_file.write_text(node_id)
return node_id
def collect_capabilities(self):
"""Збирає інформацію про систему"""
capabilities = {
"hostname": socket.gethostname(),
"ip_address": self.get_public_ip(),
"local_ip": self.get_local_ip(),
"os": platform.system(),
"os_version": platform.version(),
"cpu_cores": psutil.cpu_count(),
"ram_gb": round(psutil.virtual_memory().total / (1024**3), 2),
"disk_gb": round(psutil.disk_usage('/').total / (1024**3), 2),
"gpu": self.detect_gpu(),
"ollama": self.check_ollama(),
}
return capabilities
def register(self):
"""Реєстрація в Node Registry"""
payload = {
"node_id": self.node_id,
"capabilities": self.collect_capabilities(),
"status": "online"
}
response = requests.post(
f"{self.registry_url}/api/v1/nodes/register",
json=payload,
timeout=10
)
response.raise_for_status()
return response.json()
def start_heartbeat(self):
"""Запускає heartbeat loop"""
import asyncio
asyncio.run(self.heartbeat_loop())
async def heartbeat_loop(self):
"""Безкінечний loop heartbeat"""
while True:
try:
metrics = self.collect_metrics()
requests.post(
f"{self.registry_url}/api/v1/nodes/heartbeat",
json={"node_id": self.node_id, "metrics": metrics},
timeout=5
)
except Exception as e:
print(f"Heartbeat failed: {e}")
await asyncio.sleep(30)
# ... (інші методи)
if __name__ == "__main__":
bootstrap = NodeBootstrap("http://144.76.224.179:9205")
print(f"🔧 Registering node: {bootstrap.node_id}")
result = bootstrap.register()
print(f"✅ Registered successfully!")
print(f" Node ID: {result['node_id']}")
print(f" API Key: {result['api_key']}")
print("💓 Starting heartbeat...")
bootstrap.start_heartbeat()
```
### Файл 2: `node_discovery.py` (Пошук нод)
```python
"""
Пошук доступних нод в мережі
"""
import requests
from typing import List, Dict, Optional
class NodeDiscovery:
def __init__(self, registry_url):
self.registry_url = registry_url
def find_nodes(
self,
role: Optional[str] = None,
capability: Optional[str] = None,
status: str = "online"
) -> List[Dict]:
"""Знайти ноди за критеріями"""
params = {"status": status}
if role:
params["role"] = role
if capability:
params["capability"] = capability
response = requests.get(
f"{self.registry_url}/api/v1/nodes/discover",
params=params
)
response.raise_for_status()
return response.json()["nodes"]
def find_best_node_for_model(self, model_name: str) -> Optional[Dict]:
"""Знайти найкращу ноду для конкретної моделі"""
nodes = self.find_nodes(capability="ollama")
for node in nodes:
if model_name in node["capabilities"].get("models", []):
return node
return None
def get_nearest_node(self, location: str = "auto") -> Dict:
"""Знайти найближчу ноду"""
response = requests.get(
f"{self.registry_url}/api/v1/nodes/discover",
params={"nearest": location}
)
response.raise_for_status()
return response.json()["nodes"][0]
# Використання
discovery = NodeDiscovery("http://144.76.224.179:9205")
# Знайти всі ноди з GPU
gpu_nodes = discovery.find_nodes(capability="gpu")
print(f"Found {len(gpu_nodes)} nodes with GPU")
# Знайти ноду з deepseek-r1:70b
node = discovery.find_best_node_for_model("deepseek-r1:70b")
if node:
print(f"Model available on: {node['node_name']}")
```
---
## 🎯 Переваги цієї архітектури
### Для розробників
-**Plug and Play** - додали ноду за 5 хвилин
-**Нульова конфігурація** - все автоматично
-**Discovery API** - легко знайти потрібну ноду
### Для системи
-**Fault tolerance** - автоматичне виявлення збоїв
-**Load balancing** - розподіл навантаження
-**Horizontal scaling** - додавай скільки потрібно нод
### Для бізнесу
-**Швидке масштабування** - від 2 до 1000 нод
-**Географічне розподілення** - ноди по всьому світу
-**Cost optimization** - використання ресурсів по потребі
---
## 📈 Roadmap
### Phase 1: Базова функціональність (ЗАРАЗ)
- [x] Node Registry Service infrastructure
- [ ] Імплементація Node Registry API
- [ ] Bootstrap agent покращений
- [ ] Heartbeat service
- [ ] Discovery API
### Phase 2: Безпека та моніторинг
- [ ] API key authentication
- [ ] mTLS certificates
- [ ] Prometheus metrics
- [ ] Grafana dashboards
- [ ] Alert system
### Phase 3: Федерація
- [ ] Multi-region registries
- [ ] Registry replication
- [ ] Geographic routing
- [ ] Latency optimization
### Phase 4: Повна децентралізація
- [ ] P2P discovery (DHT)
- [ ] Consensus protocol
- [ ] Blockchain registry (optional)
- [ ] Zero-knowledge proofs
---
## ✅ Що потрібно зробити ЗАРАЗ
### 1. Завершити Node Registry API
```bash
# Файл: services/node-registry/app/main.py
# Імплементувати endpoints:
POST /api/v1/nodes/register
POST /api/v1/nodes/heartbeat
GET /api/v1/nodes
GET /api/v1/nodes/{node_id}
GET /api/v1/nodes/discover
```
### 2. Покращити Bootstrap Agent
```bash
# Файл: tools/dagi_node_agent/bootstrap.py
# Додати:
- Auto-detection capabilities
- Ollama models scanning
- GPU detection (NVIDIA, Apple Silicon)
- Persistent node_id storage
```
### 3. Створити Frontend для моніторингу
```bash
# Додати сторінку в React:
/nodes/registry
- Список всіх нод
- Статус (online/offline)
- Capabilities
- Real-time heartbeat
```
---
## 🎯 Відповідь на ваше питання
### Чи можливо автоматизувати додавання нод?
**ТАК! Це повністю можливо і вже частково реалізовано!**
**Що вже є:**
- ✅ Node Registry Service (infraструктура готова)
- ✅ Bootstrap Agent (базова версія)
- ✅ Database schema для нод
- ✅ Docker конфігурація
**Що треба:**
- 🔧 Завершити Node Registry API (1-2 дні)
- 🔧 Покращити Bootstrap Agent (1 день)
- 🔧 Додати heartbeat service (1 день)
- 🔧 Створити Discovery API (1 день)
**Результат:**
```bash
# На будь-якій новій ноді просто запускаєте:
./scripts/join-network.sh
# І нода автоматично:
# 1. Реєструється
# 2. Починає heartbeat
# 3. Стає доступною в мережі
# 4. З'являється в dashboard
```
---
**Статус:****Архітектура готова, залишилась імплементація!**
**Часова оцінка:** 4-5 днів розробки
**Складність:** Середня (Node Registry API + Bootstrap покращення)
**Коли буде готово - у вас буде plug-and-play мережа штучного інтелекту! 🚀**