Scaling Blockchain Infrastructure: From Node to WebSocket
Infrastructure that worked fine at 100 users starts crumbling at 10,000. The blockchain stack is specific: the bottleneck is often not where you expect – not the database, not the CPU – but the RPC node that can't keep up with eth_getLogs, or the indexer lagging behind by 50 blocks, or the WebSocket handler dropping connections under load. Scaling blockchain infrastructure is a separate discipline with unconventional patterns. We've been doing this for over 5 years and guarantee your infrastructure can handle any load – contact us, we'll assess your project free of charge.
Why Scaling Blockchain Infrastructure Is a Separate Discipline
Unlike classic web, there are failure points that can't be fixed by simply adding servers: chain state, WebSocket limits, immutable data on nodes. Each layer requires its own approach – from node pool to event-driven indexing.
Diagnosis: Where the Real Bottleneck Is
Before scaling anything – measure. Typical bottlenecks: latency per RPC method, indexer queue depth, lag between node head and DB head, WebSocket connection throughput. We use Prometheus and ready dashboards for metrics collection – included in the scope of work.
// Instrumentation of RPC calls class InstrumentedProvider { private metrics: Map<string, number[]> = new Map(); async call(method: string, params: any[]): Promise<any> { const start = performance.now(); try { const result = await this.provider.send(method, params); this.record(method, performance.now() - start); return result; } catch (err) { this.recordError(method); throw err; } } getPercentiles(method: string) { const samples = (this.metrics.get(method) || []).sort((a, b) => a - b); return { p50: samples[Math.floor(samples.length * 0.5)], p95: samples[Math.floor(samples.length * 0.95)], p99: samples[Math.floor(samples.length * 0.99)], count: samples.length, }; } } How to Scale the RPC Layer
Node Pool with Load Balancing
A single node is a single point of failure and bottleneck. Minimum production configuration: three nodes with health checks and round-robin skipping unhealthy nodes. For stateful operations (subscriptions, pending transactions) – sticky routing. The example code below – we use it in every project.
class NodePool { private nodes: RpcNode[]; private currentIndex = 0; private healthStatus: Map<string, boolean> = new Map(); async sendRequest(method: string, params: any[]): Promise<any> { for (let i = 0; i < this.nodes.length; i++) { const node = this.nodes[this.currentIndex % this.nodes.length]; this.currentIndex++; if (!this.healthStatus.get(node.url)) continue; try { return await node.send(method, params); } catch (err) { this.healthStatus.set(node.url, false); setTimeout(() => this.healthStatus.set(node.url, true), 30_000); } } throw new Error('All nodes unhealthy'); } } Caching RPC Responses
Many requests are identical and cacheable: eth_chainId (24 hours), eth_getCode (1 hour – contract code doesn't change), eth_getBlockByNumber for non-latest (1 minute), eth_getTransactionReceipt (5 minutes after finalization). Never cache latest or pending. Use Redis – this reduces requests to the node by 80%.
const CACHEABLE_METHODS: Record<string, number> = { 'eth_chainId': 86400, 'eth_getCode': 3600, 'eth_getBlockByNumber': 60, 'eth_getTransactionReceipt': 300, }; class CachingRpcProxy { async send(method: string, params: any[]): Promise<any> { const ttl = CACHEABLE_METHODS[method]; if (!ttl) return this.upstream.send(method, params); if (params.includes('latest') || params.includes('pending')) { return this.upstream.send(method, params); } const cacheKey = `rpc:${method}:${JSON.stringify(params)}`; const cached = await this.redis.get(cacheKey); if (cached) return JSON.parse(cached); const result = await this.upstream.send(method, params); await this.redis.setex(cacheKey, ttl, JSON.stringify(result)); return result; } } Indexing: From Polling to Event-Driven
The Polling Problem
Polling every 5 seconds for 10,000 addresses – 2,000 requests per second. The node gets overwhelmed. Switch to event-driven model via EVM logs: one getLogs for a block range replaces thousands of individual requests. Savings – up to 90% RPC load.
The Graph for Complex Indexing
For aggregations by user, historical data – The Graph subgraph. Self-hosted Graph Node on PostgreSQL 14+ with sufficient I/O. Included in typical scope of work: subgraph setup, deployment, monitoring.
WebSocket: Scaling Subscriptions
WebSocket is stateful – nginx round-robin doesn't work. Use Redis pub/sub: a separate service publishes events (new block, transaction) to Redis, and WS servers subscribe and distribute to their clients. Adding another WS server – the only thing needed for horizontal scaling.
Managing Node Load
Request coalescing – if 100 requests simultaneously ask for the same resource, combine them into one RPC call. Multicall – one HTTP request instead of 100 for balanceOf. Both patterns reduce node load tens of times.
| Problem | Solution | Complexity | RPC Load Savings |
|---|---|---|---|
| RPC node bottleneck | Node pool + balancing | Low | 50%+ |
| Repeated identical requests | Request coalescing + Redis cache | Low | 80%+ |
| 100+ addresses monitoring balances | Multicall + event indexing | Medium | 90%+ |
| WS dropping connections under load | Redis pub/sub backbone | Medium | — |
| Slow historical queries | Erigon/Reth archive + query optimization | Medium | 70%+ |
| Complex analytics on-chain data | The Graph subgraph | High | — |
What's Included in Our Work
- audit of current architecture with measurement of latency, throughput, lag;
- solution design for your stack (Ethereum, Polygon, Arbitrum, Solana);
- implementation: node pool, caching, event-driven indexing, WebSocket gateway;
- monitoring integration (Grafana, Prometheus, alerts);
- documentation and access transfer;
- team training on new infrastructure;
- one month of post-launch support.
Process
- Analytics – profile current infrastructure, identify bottlenecks.
- Design – select patterns, prepare schema.
- Implementation – write code, configure services.
- Testing – load tests on your scenarios.
- Deployment and monitoring – launch with observation in the first days.
Estimated Timelines
From 2 to 6 weeks depending on complexity and number of networks. Cost is calculated individually after the audit – contact us, we'll estimate within 1-2 days.
We work with Ethereum, Polygon, Arbitrum, Optimism, BNB Chain, Solana. Experience – 10+ projects, over 5 years on the market. Quality guaranteed: all solutions undergo review and testing.







