Scaling Blockchain Infrastructure: From Node to WebSocket

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

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1450
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1309
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1270
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1011

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

  1. Analytics – profile current infrastructure, identify bottlenecks.
  2. Design – select patterns, prepare schema.
  3. Implementation – write code, configure services.
  4. Testing – load tests on your scenarios.
  5. 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.