Scaling Infrastructure

Strategies for scaling RPC endpoints, load balancing, caching, and handling high-traffic blockchain applications.

Scaling Strategies

Load Balancing

Distribute RPC requests across multiple nodes to handle high traffic.

Benefits

High availabilityFault toleranceBetter throughput

Tools

NginxHAProxyAWS ALBCloudflare

Caching Layer

Cache frequently requested data to reduce node load and improve response times.

Benefits

Faster responsesReduced loadCost savings

Tools

RedisVarnishCloudflareCustom middleware

Read Replicas

Use multiple read-only nodes to scale read operations independently.

Benefits

Unlimited readsGeographic distributionBackup nodes

Tools

GethErigonAny execution client

Connection Pooling

Reuse connections to nodes instead of creating new ones for each request.

Benefits

Lower latencyResource efficiencyBetter throughput

Tools

Web3.js poolsCustom poolingPgBouncer-style

Nginx Load Balancer

nginx.conf
upstream ethereum_nodes {
    least_conn;  # Route to node with fewest connections

    server node1.internal:8545 weight=5;
    server node2.internal:8545 weight=5;
    server node3.internal:8545 weight=3 backup;

    keepalive 32;
}

# Rate limiting zone
limit_req_zone $binary_remote_addr zone=rpc_limit:10m rate=100r/s;

server {
    listen 80;
    server_name rpc.yourdomain.com;

    location / {
        # Rate limiting
        limit_req zone=rpc_limit burst=50 nodelay;

        # Proxy settings
        proxy_pass http://ethereum_nodes;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # Timeouts
        proxy_connect_timeout 5s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;

        # CORS headers
        add_header 'Access-Control-Allow-Origin' '*' always;
        add_header 'Access-Control-Allow-Methods' 'POST, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'Content-Type' always;

        if ($request_method = 'OPTIONS') {
            return 204;
        }
    }

    # Health check endpoint
    location /health {
        access_log off;
        return 200 "OK";
    }
}

Least Connections

Routes to node with fewest active connections

Rate Limiting

100 req/s with burst of 50 per IP

Keep-Alive

Connection pooling for better performance

RPC Response Caching

Many RPC methods return immutable data or data that can be safely cached for short periods. Implementing a caching layer can dramatically reduce load on your nodes.

MethodTTLNotes
eth_chainIdChain ID never changes
eth_blockNumber1-3sCache for block time
eth_getBlockByNumber (finalized)Finalized blocks are immutable
eth_getTransactionReceiptReceipts are immutable
eth_getBalance~12sCache per block
eth_call~12sCache per block for same params
eth_gasPrice3-10sShort cache for gas estimates
eth_getLogsHistorical logs are immutable
cache-middleware.ts (example)
import Redis from 'ioredis';

const redis = new Redis(process.env.REDIS_URL);

const CACHE_TTL: Record<string, number> = {
  'eth_chainId': -1,              // Infinite
  'eth_blockNumber': 3,           // 3 seconds
  'eth_gasPrice': 10,             // 10 seconds
  'eth_getBlockByNumber': -1,     // Infinite for finalized
  'eth_getTransactionReceipt': -1 // Infinite
};

export async function cacheMiddleware(method: string, params: any[]) {
  const ttl = CACHE_TTL[method];
  if (ttl === undefined) return null;  // Not cacheable

  const cacheKey = `rpc:${method}:${JSON.stringify(params)}`;

  // Try cache first
  const cached = await redis.get(cacheKey);
  if (cached) {
    return JSON.parse(cached);
  }

  // Call node
  const result = await callNode(method, params);

  // Cache result
  if (ttl === -1) {
    await redis.set(cacheKey, JSON.stringify(result));
  } else {
    await redis.setex(cacheKey, ttl, JSON.stringify(result));
  }

  return result;
}

Multi-Region Architecture

For global applications, deploy nodes in multiple regions and route users to the nearest one:

US East

Primary region

EU West

European users

Asia Pacific

Asian users

Use GeoDNS or Cloudflare Load Balancing:

rpc.yourdomain.com → Routes to nearest region based on user IP

WebSocket Considerations

WebSocket connections for subscriptions (newHeads, logs) require special handling:

Sticky Sessions

Use session affinity to keep WebSocket connections on the same node

Connection Limits

Set limits per node (typically 1000-5000 concurrent connections)

Pub/Sub Fan-out

Consider using Redis pub/sub to fan out events from a single node subscription

WebSocket Load Balancing

Standard HTTP load balancers may not work well with WebSockets. Use sticky sessions or dedicated WebSocket proxies like Nginx with ip_hash.

Capacity Planning

ScaleRequests/secNodesInfrastructure
Small< 1001-2 nodesSingle node with backup
Medium100 - 1,0003-5 nodesLoad balancer + caching
Large1,000 - 10,00010-20 nodesMulti-region + aggressive caching
Enterprise> 10,00050+ nodesCustom solution / managed service