Запуск блокчейн-ноды руками — простая задача для одной ноды. Когда их становится сотня, это уже инфраструктурный проект с 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 дней создаём актуальную копию базы данных, инкрементальные дифы — ежедневно. 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. Свяжитесь с нами — оценим вашу задачу и предложим оптимальное решение.







