Scaling

This guide covers scaling Azu applications to handle increased load, from vertical scaling to horizontal scaling and distributed architectures.

Scaling Overview

Scaling Approaches

Vertical Scaling (Scale Up)

Increasing the resources of a single server instance.

# Configure for high-performance single instance
Azu.configure do |config|
  config.worker_threads = 8
  config.database_pool_size = 50
  config.cache_pool_size = 20
  config.request_timeout = 60.seconds
end

Horizontal Scaling (Scale Out)

Adding more server instances to handle increased load.

# docker-compose.scale.yml
version: "3.8"

services:
  app:
    deploy:
      replicas: 5
      resources:
        limits:
          memory: 1G
          cpus: "0.5"
        reservations:
          memory: 512M
          cpus: "0.25"

Load Balancing

Nginx Load Balancer

# nginx.conf
upstream azu_app {
    # Round-robin load balancing
    server app1:3000;
    server app2:3000;
    server app3:3000;
    server app4:3000;
    server app5:3000;

    # Health checks
    health_check;
}

server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://azu_app;
        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
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    }
}

HAProxy Configuration

# haproxy.cfg
global
    daemon
    maxconn 4096

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend azu_frontend
    bind *:80
    default_backend azu_backend

backend azu_backend
    balance roundrobin
    option httpchk GET /health

    server app1 app1:3000 check
    server app2 app2:3000 check
    server app3 app3:3000 check
    server app4 app4:3000 check
    server app5 app5:3000 check

Database Scaling

Read Replicas

# Database configuration with read replicas
Azu.configure do |config|
  config.database_url = "postgresql://user:pass@master:5432/app"
  config.database_read_replicas = [
    "postgresql://user:pass@replica1:5432/app",
    "postgresql://user:pass@replica2:5432/app",
    "postgresql://user:pass@replica3:5432/app"
  ]
  config.database_load_balancing = :round_robin
end

Connection Pooling

# PgBouncer configuration
Azu.configure do |config|
  config.database_pool_size = 20
  config.database_pool_timeout = 5.seconds
  config.database_statement_timeout = 30.seconds
  config.database_idle_timeout = 10.minutes
end

Database Sharding

# Database sharding configuration
Azu.configure do |config|
  config.database_shards = {
    "shard1" => "postgresql://user:pass@shard1:5432/app",
    "shard2" => "postgresql://user:pass@shard2:5432/app",
    "shard3" => "postgresql://user:pass@shard3:5432/app"
  }
  config.database_shard_key = "user_id"
end

Caching Strategies

Redis Cluster

# Redis cluster configuration
Azu.configure do |config|
  config.redis_cluster_nodes = [
    "redis://node1:6379",
    "redis://node2:6379",
    "redis://node3:6379",
    "redis://node4:6379",
    "redis://node5:6379",
    "redis://node6:6379"
  ]
  config.redis_cluster_replicas = 1
end

Cache Warming

# Cache warming strategy
class CacheWarmer
  def self.warm_cache
    # Warm frequently accessed data
    warm_user_cache
    warm_product_cache
    warm_category_cache
  end

  private def self.warm_user_cache
    User.all.each do |user|
      Azu::Cache.set("user:#{user.id}", user.to_json, 1.hour)
    end
  end
end

Cache Invalidation

# Cache invalidation strategy
class CacheInvalidator
  def self.invalidate_user_cache(user_id)
    Azu::Cache.delete("user:#{user_id}")
    Azu::Cache.delete("user:#{user_id}:profile")
    Azu::Cache.delete("user:#{user_id}:settings")
  end
end

Session Management

Redis Sessions

# Redis session configuration
Azu.configure do |config|
  config.session_store = :redis
  config.session_redis_url = "redis://localhost:6379/1"
  config.session_ttl = 24.hours
  config.session_cookie_secure = true
  config.session_cookie_httponly = true
end

Session Clustering

# Session clustering for multiple instances
class SessionManager
  def self.create_session(user_id)
    session_id = SecureRandom.uuid
    session_data = {
      "user_id" => user_id,
      "created_at" => Time.utc.to_s,
      "expires_at" => (Time.utc + 24.hours).to_s
    }

    Azu::Cache.set("session:#{session_id}", session_data.to_json, 24.hours)
    session_id
  end

  def self.get_session(session_id)
    session_data = Azu::Cache.get("session:#{session_id}")
    return nil unless session_data

    JSON.parse(session_data)
  end
end

WebSocket Scaling

WebSocket Load Balancing

# WebSocket load balancing
upstream websocket_backend {
    server app1:3000;
    server app2:3000;
    server app3:3000;
}

server {
    location /ws {
        proxy_pass http://websocket_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        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;
    }
}

WebSocket Clustering

# WebSocket clustering with Redis
class WebSocketCluster
  def self.broadcast_to_channel(channel, message)
    # Publish to Redis for other instances
    Azu::Cache.publish("websocket:#{channel}", message)
  end

  def self.handle_redis_message(channel, message)
    # Handle message from other instances
    WebSocketManager.broadcast_to_local_clients(channel, message)
  end
end

Microservices Architecture

Service Discovery

# Service discovery configuration
Azu.configure do |config|
  config.service_registry = "consul://localhost:8500"
  config.service_name = "azu-app"
  config.service_port = 3000
  config.service_health_check = "/health"
end

API Gateway

# API Gateway configuration
class APIGateway
  def self.route_request(request)
    service = determine_service(request.path)
    forward_request(service, request)
  end

  private def self.determine_service(path)
    case path
    when /^\/api\/users/
      "user-service"
    when /^\/api\/products/
      "product-service"
    when /^\/api\/orders/
      "order-service"
    else
      "main-service"
    end
  end
end

Container Orchestration

Kubernetes Deployment

# k8s-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: azu-app
spec:
  replicas: 5
  selector:
    matchLabels:
      app: azu-app
  template:
    metadata:
      labels:
        app: azu-app
    spec:
      containers:
        - name: azu-app
          image: azu-app:latest
          ports:
            - containerPort: 3000
          env:
            - name: AZU_ENVIRONMENT
              value: "production"
            - name: DATABASE_URL
              valueFrom:
                secretKeyRef:
                  name: azu-secrets
                  key: database-url
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 5

Kubernetes Service

# k8s-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: azu-app-service
spec:
  selector:
    app: azu-app
  ports:
    - port: 80
      targetPort: 3000
  type: LoadBalancer

Kubernetes HPA

# k8s-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: azu-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: azu-app
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

Performance Monitoring

Application Metrics

# Performance monitoring
class PerformanceMonitor
  def self.track_request_time(endpoint, duration)
    Azu::Cache.increment("metrics:request_time:#{endpoint}", duration)
  end

  def self.track_memory_usage
    memory_usage = System.memory_usage
    Azu::Cache.set("metrics:memory_usage", memory_usage.to_s, 1.minute)
  end

  def self.track_database_queries
    Azu::Cache.increment("metrics:database_queries")
  end
end

Prometheus Metrics

# Prometheus metrics endpoint
struct MetricsEndpoint
  include Azu::Endpoint

  get "/metrics"

  def call
    metrics = {
      "http_requests_total" => get_request_count,
      "http_request_duration_seconds" => get_request_duration,
      "memory_usage_bytes" => get_memory_usage,
      "database_connections_active" => get_active_connections
    }

    response.header("Content-Type", "text/plain")
    response.body(format_prometheus_metrics(metrics))
  end
end

Auto-scaling

CPU-based Scaling

# CPU-based auto-scaling
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: azu-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: azu-app
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Custom Metrics Scaling

# Custom metrics auto-scaling
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: azu-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: azu-app
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "100"

Disaster Recovery

Multi-region Deployment

# Multi-region deployment
apiVersion: v1
kind: ConfigMap
metadata:
  name: azu-app-config
data:
  primary_region: "us-east-1"
  backup_region: "us-west-2"
  failover_threshold: "5"

Backup Strategy

# Automated backup strategy
class BackupManager
  def self.create_backup
    timestamp = Time.utc.to_s("%Y%m%d_%H%M%S")

    # Database backup
    create_database_backup(timestamp)

    # Application backup
    create_application_backup(timestamp)

    # Upload to cloud storage
    upload_to_cloud_storage(timestamp)
  end

  private def self.create_database_backup(timestamp)
    system("pg_dump app_prod > backup_#{timestamp}.sql")
  end

  private def self.create_application_backup(timestamp)
    system("tar -czf app_backup_#{timestamp}.tar.gz /var/www/azu-app")
  end
end

Cost Optimization

Resource Optimization

# Resource optimization
apiVersion: apps/v1
kind: Deployment
metadata:
  name: azu-app
spec:
  template:
    spec:
      containers:
        - name: azu-app
          resources:
            requests:
              memory: "128Mi"
              cpu: "100m"
            limits:
              memory: "256Mi"
              cpu: "200m"

Spot Instances

# Spot instances for cost savings
apiVersion: apps/v1
kind: Deployment
metadata:
  name: azu-app
spec:
  template:
    spec:
      nodeSelector:
        node.kubernetes.io/instance-type: "spot"
      tolerations:
        - key: "spot"
          operator: "Equal"
          value: "true"
          effect: "NoSchedule"

Next Steps

Last updated

Was this helpful?