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

20 KiB
Raw Permalink Blame History

🌐 Децентралізована мережа нод - Архітектура автоматичного підключення

Дата: 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

База даних:

-- 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:

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
Статус: Існує, потрібне покращення

Як працює:

# Запуск на новій ноді
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

Механізм:

# Кожні 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:

# Знайти ноду з 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:

{
  "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: Встановлення на новій ноді

# На НОДА3
git clone git@github.com:IvanTytar/microdao-daarion.git
cd microdao-daarion
pip install -r requirements.txt

Крок 2: Конфігурація (один файл)

# Створити .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: Автоматична реєстрація

# Запустити 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: Перевірка

# На будь-якій ноді
curl http://144.76.224.179:9205/api/v1/nodes

# Побачите НОДА3 в списку!

🔐 Безпека та автентифікація

Рівень 1: API Key (Базовий)

# При реєстрації генерується 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)

# Кожна нода має свій сертифікат
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)

# В 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 (Покращений)

#!/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 (Пошук нод)

"""
Пошук доступних нод в мережі
"""
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: Базова функціональність (ЗАРАЗ)

  • 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

# Файл: 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

# Файл: tools/dagi_node_agent/bootstrap.py
# Додати:
- Auto-detection capabilities
- Ollama models scanning
- GPU detection (NVIDIA, Apple Silicon)
- Persistent node_id storage

3. Створити Frontend для моніторингу

# Додати сторінку в 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 день)

Результат:

# На будь-якій новій ноді просто запускаєте:
./scripts/join-network.sh

# І нода автоматично:
# 1. Реєструється
# 2. Починає heartbeat
# 3. Стає доступною в мережі
# 4. З'являється в dashboard

Статус: Архітектура готова, залишилась імплементація!
Часова оцінка: 4-5 днів розробки
Складність: Середня (Node Registry API + Bootstrap покращення)

Коли буде готово - у вас буде plug-and-play мережа штучного інтелекту! 🚀