Запуск блокчейн-ноди вручну — просте завдання для однієї ноди. Коли їх стає сотня, це вже інфраструктурний проєкт з K8s, StatefulSet, snapshot bootstrap та білінгом. Ми займаємося Node-as-a-Service розробкою під ключ і побудували не одну таку платформу: від вибору клієнтів (Ethereum, Solana, BNB) до production-grade API Gateway з rate limiting та compute units. З нашої практики: один із клієнтів Fortune 500 замінив ручне управління нодами на NaaS — витрати на інфраструктуру знизилися на 40%, що принесло економію $15 000 на місяць, а річна економія перевищила $180 000. Зв'яжіться з нами — оцінимо ваш проєкт за 2 дні.
Як працює Node-as-a-Service платформа?
NaaS-платформа надає клієнтам єдиний RPC-ендпоінт, за яким прихована оркестрація десятків і сотень нод. Кожна нода запускається в K8s як StatefulSet з власним PersistentVolumeClaim. Для бюджетного сегменту ноди розділяються між клієнтами (shared), для вимогливих — виділяються цілком (dedicated) або кластерами з балансуванням (node clusters).
Чому стандартний Kubernetes не підходить для блокчейн-нод?
Звичайний Deployment в K8s не враховує специфіку блокчейн-нод, тому Kubernetes для блокчейн-інфраструктури вимагає використання StatefulSet. Ноди потребують stateful-сховища (сотні гігабайт), фіксованих P2P-портів та захисту від перезапусків без втрати синхронізації. Використовуємо StatefulSet з PVC та headless service — це гарантує, що при збої под не перествориться на іншому вузлі, а дані залишаться прив'язаними до storage.
Приклад конфігурації StatefulSet для Ethereum ноди:
apiVersion: apps/v1 kind: StatefulSet metadata: name: ethereum-geth spec: serviceName: "geth" replicas: 1 selector: matchLabels: app: ethereum-geth template: spec: containers: - name: geth image: ethereum/client-go:v1.13.14 args: ["--datadir=/data", "--http", "--http.addr=0.0.0.0", "--http.vhosts=*", "--http.api=eth,net,web3,txpool", "--ws", "--ws.addr=0.0.0.0", "--maxpeers=50", "--cache=4096"] ports: - containerPort: 8545 - containerPort: 8546 - containerPort: 30303 protocol: TCP - containerPort: 30303 protocol: UDP volumeMounts: - name: data mountPath: /data resources: requests: memory: "16Gi" cpu: "4" limits: memory: "32Gi" cpu: "8" volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: "fast-nvme" resources: requests: storage: 3Ti Проблеми, які вирішуємо
Snapshot bootstrapping
Синхронізація Ethereum mainnet з нуля (snap sync) займає 12–24 години, а архівна нода (archive node) — до 5 тижнів. Для NaaS це критично: клієнт платить з першої хвилини. Ми використовуємо snapshot distribution: кожні 7 днів створюємо актуальну копію бази даних, інкрементальні diffs — щоденно. Bootstrap ноди з snapshot займає 10–15 хвилин.
Порівняння режимів синхронізації нод Ethereum:
| Режим | Розмір даних | Час синхронізації | RPC-доступність |
|---|---|---|---|
| Snap sync | ~500 GB | 12–24 год | Full |
| Full sync | ~1.2 TB | 3–5 днів | Архів |
| Archive (архівна нода) | ~15 TB | 5–7 тижнів | Архів + трасування |
Ізоляція клієнтів
В одній платформі можуть працювати як стартапи з free tier, так і enterprise з гарантіями SLA. Розділяємо ресурси через три моделі мультитенантності, кожна зі своїм підходом до білінгу блокчейн-інфраструктури.
| Модель | Ізоляція | Типовий кейс | Приклад ціноутворення |
|---|---|---|---|
| Shared | Низька (один процес) | Free tier, тестові проєкти | Оплата за CU |
| Dedicated | Висока (виділена нода) | Production, стабільний RPC | Фіксована ставка |
| Node cluster | Максимальна (репліки + LB) | Enterprise, HA | Індивідуальний розрахунок |
Для білінгу блокчейн-інфраструктури використовуємо compute units — кожен RPC-метод має вагу в CU: eth_blockNumber — 10 CU, eth_call — 26 CU, trace_replayTransaction — 75 CU.
Як ми це робимо: стек і кейси
RPC-проксі з інтелектуальною маршрутизацією
Кастомний проксі на Go фільтрує небезпечні методи (наприклад, debug_* тільки для premium), розподіляє запити між archive та full нодами та кешує відповіді (TTL — 1 секунда для eth_blockNumber). Rate limiting реалізовано через Redis sliding window — він точніше token bucket для RPC-навантажень.
// Приклад RPC проксі з routing logic package proxy type RPCRouter struct { archivePool NodePool fullNodePool NodePool cacheClient *redis.Client } var archiveMethods = map[string]bool{ "eth_getBalance": true, "eth_call": true, "eth_getStorageAt": true, "trace_call": true, "trace_replayTransaction": true, } func (r *RPCRouter) Route(req *RPCRequest) NodePool { if archiveMethods[req.Method] { if req.RequiresHistoricalBlock() { return r.archivePool } } return r.fullNodePool } func (r *RPCRouter) Handle(w http.ResponseWriter, req *RPCRequest, apiKey string) { cacheKey := req.CacheKey() if cached, err := r.cacheClient.Get(ctx, cacheKey).Bytes(); err == nil { w.Write(cached) return } pool := r.Route(req) node := pool.GetHealthyNode() resp := node.Forward(req) if req.IsCacheable() { r.cacheClient.Set(ctx, cacheKey, resp, req.CacheTTL()) } r.billing.RecordRequest(apiKey, req.Method, resp.ComputeUnits()) w.Write(resp) } Health checking з урахуванням стану ноди
Ping не гарантує, що нода обробляє запити. Використовуємо перевірку синхронізації: якщо SyncProgress не nil або блок старше 2 хвилин — нода виключається з пулу. Health перевірки запускаємо кожні 15 секунд.
type NodeHealthChecker struct { client *ethclient.Client } func (h *NodeHealthChecker) IsHealthy(ctx context.Context) (bool, error) { syncing, err := h.client.SyncProgress(ctx) if err != nil { return false, err } if syncing != nil { return false, fmt.Errorf("node is syncing: %d/%d", syncing.CurrentBlock, syncing.HighestBlock) } header, err := h.client.HeaderByNumber(ctx, nil) if err != nil { return false, err } blockAge := time.Since(time.Unix(int64(header.Time), 0)) if blockAge > 2*time.Minute { return false, fmt.Errorf("block too old: %v", blockAge) } return true, nil } Rate limiting на Redis
func (rl *RateLimiter) Allow(ctx context.Context, apiKey string, rps int) (bool, error) { now := time.Now().UnixMilli() window := int64(1000) pipe := rl.redis.Pipeline() pipe.ZRemRangeByScore(ctx, apiKey, "0", strconv.FormatInt(now-window, 10)) pipe.ZCard(ctx, apiKey) pipe.ZAdd(ctx, apiKey, redis.Z{Score: float64(now), Member: now}) pipe.Expire(ctx, apiKey, 2*time.Second) results, err := pipe.Exec(ctx) count := results[1].(*redis.IntCmd).Val() return count < int64(rps), nil } Білінг на основі compute units
CREATE TABLE api_keys ( id UUID PRIMARY KEY, customer_id UUID NOT NULL, key_hash BYTEA NOT NULL, tier VARCHAR(20) NOT NULL, rate_limit_rps INTEGER NOT NULL, monthly_cu_limit BIGINT, node_type VARCHAR(20) NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW() ); CREATE TABLE usage_records ( id BIGSERIAL PRIMARY KEY, api_key_id UUID NOT NULL REFERENCES api_keys(id), method VARCHAR(100) NOT NULL, chain_id INTEGER NOT NULL, compute_units INTEGER NOT NULL, response_time_ms INTEGER, recorded_at TIMESTAMPTZ DEFAULT NOW() ); CREATE INDEX idx_usage_billing ON usage_records (api_key_id, recorded_at); Як ми будуємо NaaS-платформу: етапи та терміни
- Аналітика та аудит (1–2 тижні): визначаємо цільові блокчейни, модель мультитенантності, вимоги до SLA та регіону.
- Проектування архітектури (1–2 тижні): обираємо клієнти (Geth, Reth, Erigon, Solana Agave), готуємо схеми K8s, API Gateway, білінгу.
- Реалізація core infrastructure (4–6 тижнів): StatefulSet templates, snapshot bootstrap pipeline, health checker.
- Розробка API Gateway та білінгу (6–8 тижнів): RPC проксі, rate limiting, compute units, інтеграція Stripe.
- Observability та self-service portal (6–9 тижнів): Prometheus + Grafana, alerting, веб-інтерфейс для управління ключами та перегляду метрик.
- Тестування та деплой (2–3 тижні): навантажувальне тестування, security audit, запуск у production.
Разом: від 16 до 23 тижнів до production-ready платформи. Якщо ви хочете прискорити етап, зв'яжіться з нашими інженерами — ми запропонуємо відповідний темп.
Що входить у роботу
- Документація: архітектурна схема, інструкції з додавання нових ланцюгів, runbook для on-call.
- Доступи: репозиторій з шаблонами, CI/CD pipeline, моніторинг (Grafana dashboards).
- Навчання: 2–3 сесії для вашої команди (DevOps та backend).
- Підтримка: 3 місяці після запуску (багфікс, консультації).
Типові помилки при розробці NaaS
- Використання hostNetwork для P2P портів — втрачається ізоляція. Краще NodePort або LoadBalancer з фіксованим портом на ноду.
- Відсутність кешування частих RPC-методів (eth_chainId, eth_blockNumber) — збільшує навантаження на ноду та білінг.
- Health check тільки по TCP — нода може бути живою, але відставати від мережі на сотні блоків.
Якщо ви зіткнулися з подібними проблемами або хочете уникнути їх, замовте розробку NaaS-платформи у нас. Детальніше про StatefulSet. Ми накопичили 10+ років досвіду в блокчейн-інфраструктурі та реалізували 50+ проєктів, включаючи платформи для Fortune 500. Зв'яжіться з нами — оцінимо вашу задачу та запропонуємо оптимальне рішення.







