Scaling & Load Management

Scale your application to handle increased traffic and optimize performance under load.

Scaling & Load Management

Horizontal Scaling

Load Balancing

Distribute traffic across multiple application instances.

# nginx.conf - Load balancer configuration
upstream app_servers {
    server app1.example.com:3000;
    server app2.example.com:3000;
    server app3.example.com:3000;
    
    # Health check
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://app_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # Load balancing method
        # ip_hash; # Session affinity
        # least_conn; # Least connections
    }
}

Auto-Scaling Configuration

Set up automatic scaling based on metrics.

# docker-compose.yml with scaling
version: '3.8'
services:
  app:
    image: your-app:latest
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

Vertical Scaling

Resource Optimization

Optimize server resources for better performance.

// next.config.mjs - Performance optimizations
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Enable compression
  compress: true,
  
  // Optimize bundle
  swcMinify: true,
  
  // Enable experimental features
  experimental: {
    // Reduce bundle size
    optimizePackageImports: ['@mui/material', 'lodash'],
    
    // Improve build performance
    turbo: {
      rules: {
        '*.svg': {
          loaders: ['@svgr/webpack'],
          as: '*.js',
        },
      },
    },
  },
  
  // Image optimization
  images: {
    formats: ['image/webp', 'image/avif'],
    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
  },
}

export default nextConfig

Memory Management

Optimize memory usage and prevent leaks.

// lib/memory-management.ts
export class MemoryManager {
  private static instance: MemoryManager
  private cache = new Map<string, any>()
  private readonly maxCacheSize = 1000
  
  static getInstance(): MemoryManager {
    if (!MemoryManager.instance) {
      MemoryManager.instance = new MemoryManager()
    }
    return MemoryManager.instance
  }
  
  set(key: string, value: any): void {
    // Implement LRU cache eviction
    if (this.cache.size >= this.maxCacheSize) {
      const firstKey = this.cache.keys().next().value
      this.cache.delete(firstKey)
    }
    this.cache.set(key, value)
  }
  
  get(key: string): any {
    const value = this.cache.get(key)
    if (value) {
      // Move to end (most recently used)
      this.cache.delete(key)
      this.cache.set(key, value)
    }
    return value
  }
  
  clear(): void {
    this.cache.clear()
  }
  
  getMemoryUsage(): NodeJS.MemoryUsage {
    return process.memoryUsage()
  }
}

Database Scaling

Read Replicas

Scale database reads with replica servers.

// lib/database-scaling.ts
import { Pool } from 'pg'

export class DatabaseManager {
  private writePool: Pool
  private readPools: Pool[]
  private currentReadIndex = 0
  
  constructor() {
    // Master database for writes
    this.writePool = new Pool({
      connectionString: process.env.DATABASE_WRITE_URL,
      max: 20,
      idleTimeoutMillis: 30000,
      connectionTimeoutMillis: 2000,
    })
    
    // Read replicas
    this.readPools = [
      new Pool({
        connectionString: process.env.DATABASE_READ_URL_1,
        max: 10,
      }),
      new Pool({
        connectionString: process.env.DATABASE_READ_URL_2,
        max: 10,
      }),
    ]
  }
  
  async write(query: string, values?: any[]): Promise<any> {
    const client = await this.writePool.connect()
    try {
      return await client.query(query, values)
    } finally {
      client.release()
    }
  }
  
  async read(query: string, values?: any[]): Promise<any> {
    // Round-robin load balancing for reads
    const pool = this.readPools[this.currentReadIndex]
    this.currentReadIndex = (this.currentReadIndex + 1) % this.readPools.length
    
    const client = await pool.connect()
    try {
      return await client.query(query, values)
    } finally {
      client.release()
    }
  }
}

Connection Pooling

Optimize database connections for high load.

// lib/connection-pool.ts
import { Pool, PoolConfig } from 'pg'

const poolConfig: PoolConfig = {
  // Connection limits
  max: 20, // Maximum number of connections
  min: 5,  // Minimum number of connections
  
  // Timeouts
  connectionTimeoutMillis: 2000,
  idleTimeoutMillis: 30000,
  
  // Health checks
  allowExitOnIdle: true,
  
  // Connection validation
  application_name: 'your-app',
}

export const db = new Pool(poolConfig)

// Monitor pool health
db.on('connect', (client) => {
  console.log('New client connected:', client.processID)
})

db.on('error', (err) => {
  console.error('Database pool error:', err)
})

// Graceful shutdown
process.on('SIGINT', async () => {
  console.log('Closing database pool...')
  await db.end()
  process.exit(0)
})

Performance Monitoring

Load Testing

Test application performance under load.

// k6 load test script
import http from 'k6/http'
import { check, sleep } from 'k6'

export let options = {
  stages: [
    { duration: '2m', target: 100 }, // Ramp up
    { duration: '5m', target: 100 }, // Stay at 100 users
    { duration: '2m', target: 200 }, // Ramp up to 200 users
    { duration: '5m', target: 200 }, // Stay at 200 users
    { duration: '2m', target: 0 },   // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<2000'], // 95% of requests under 2s
    http_req_failed: ['rate<0.1'],     // Error rate under 10%
  },
}

export default function() {
  let response = http.get('https://your-app.com/api/endpoint')
  
  check(response, {
    'status is 200': (r) => r.status === 200,
    'response time < 2000ms': (r) => r.timings.duration < 2000,
  })
  
  sleep(1)
}

Metrics Collection

Monitor key performance indicators.

// lib/metrics.ts
export class MetricsCollector {
  private metrics = new Map<string, number>()
  
  increment(metric: string, value = 1): void {
    const current = this.metrics.get(metric) || 0
    this.metrics.set(metric, current + value)
  }
  
  gauge(metric: string, value: number): void {
    this.metrics.set(metric, value)
  }
  
  timing(metric: string, startTime: number): void {
    const duration = Date.now() - startTime
    this.metrics.set(metric, duration)
  }
  
  getMetrics(): Record<string, number> {
    return Object.fromEntries(this.metrics)
  }
  
  // Export metrics in Prometheus format
  exportPrometheus(): string {
    let output = ''
    for (const [key, value] of this.metrics) {
      output += `${key} ${value}\n`
    }
    return output
  }
}

// Usage example
const metrics = new MetricsCollector()

export function trackApiCall(endpoint: string) {
  return function(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const method = descriptor.value
    descriptor.value = async function(...args: any[]) {
      const startTime = Date.now()
      try {
        const result = await method.apply(this, args)
        metrics.increment(`api_calls_success_${endpoint}`)
        metrics.timing(`api_response_time_${endpoint}`, startTime)
        return result
      } catch (error) {
        metrics.increment(`api_calls_error_${endpoint}`)
        throw error
      }
    }
  }
}

CDN Configuration

Content Delivery Network

Optimize content delivery with CDN.

// next.config.mjs - CDN configuration
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    domains: ['cdn.example.com'],
    loader: 'custom',
    loaderFile: './lib/cdn-loader.js',
  },
  
  assetPrefix: process.env.NODE_ENV === 'production' 
    ? 'https://cdn.example.com' 
    : '',
}

export default nextConfig
// lib/cdn-loader.js
export default function cdnLoader({ src, width, quality }) {
  const params = new URLSearchParams({
    url: src,
    w: width.toString(),
    q: (quality || 75).toString(),
  })
  return `https://cdn.example.com/api/image?${params}`
}

Scale your application effectively to handle growing traffic while maintaining optimal performance and user experience.