Запуск блокчейн-ноди вручну — просте завдання для однієї ноди. Коли їх стає сотня, це вже інфраструктурний проєкт з 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. Зв'яжіться з нами — оцінимо вашу задачу та запропонуємо оптимальне рішення.







