Skip to main content
โšก Calmops

Edge Computing: CDN, Serverless at Edge, and Global Distribution

The cloud was just the beginning. Edge computing moves computation closer to users, reducing latency, improving performance, and enabling new use cases that aren’t possible with centralized infrastructure. This guide covers edge architecture patterns, CDN optimization, and serverless at the edge.

Understanding Edge Computing

Traditional cloud architecture sends all requests to centralized data centers. Edge computing distributes computation across a global network of edge locations:

  • CDN Points of Presence (PoPs): 250+ locations worldwide
  • Edge compute: Run code at edge locations
  • Edge databases: Data stored close to users
  • IoT edge: Compute on devices

Benefits include reduced latency (typically 10-50ms vs 100-300ms to origin), better user experience, reduced bandwidth costs, and improved resilience.

CDN Deep Dive

CDN Architecture

graph TD
    User1[User US-East] --> CDN1[Edge PoP Virginia]
    User2[User Europe] --> CDN2[Edge PoP Frankfurt]
    User3[User Asia] --> CDN3[Edge PoP Tokyo]
    
    CDN1 --> Origin[Origin Server]
    CDN2 --> Origin
    CDN3 --> Origin
    
    CDN1 --> Cache1[Cache: Static Assets]
    CDN2 --> Cache2[Cache: Static Assets]
    CDN3 --> Cache3[Cache: Static Assets]

CDN Configuration Examples

CloudFront with Origin Shield:

# CloudFront distribution
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        DefaultRootObject: index.html
        OriginShieldRegion: us-east-1
        Origins:
          - Id: MyOrigin
            DomainName: myapp.example.com
            CustomOriginConfig:
              OriginProtocolPolicy: https-only
              HTTPPort: 80
              HTTPSPort: 443
        DefaultCacheBehavior:
          TargetOriginId: MyOrigin
          ViewerProtocolPolicy: redirect-to-https
          Compress: true
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6  # Managed-CachingOptimized
        CacheBehaviors:
          - PathPattern: /api/*
            TargetOriginId: MyOrigin
            ViewerProtocolPolicy: https-only
            CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad  # Managed-CachingDisabled
          - PathPattern: /static/*
            TargetOriginId: MyOrigin
            ViewerProtocolPolicy: redirect-to-https
            CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
            OriginRequestPolicyId: 88a5e3d4-0532-4a71-aca8-bb49f4f1b8e4  # Managed-ViewerAccess

Cloudflare Page Rules:

# Cloudflare Workers + Page Rules
name: Edge Cache Config

# Cache everything at edge
routes:
  - pattern: "*.example.com/static/*"
    zone_name: "example.com"
    
workers:
  - name: cache-api
    script: |
      addEventListener('fetch', event => {
        event.respondWith(handleRequest(event.request))
      })
      
      async function handleRequest(request) {
        const cache = caches.default
        const response = await cache.match(request)
        
        if (response) {
          return response
        }
        
        const fetched = await fetch(request)
        const newResponse = fetched.clone()
        
        event.waitUntil(cache.put(request, newResponse))
        
        return fetched
      }

Cache Invalidation Strategies

# CloudFront invalidation script
import boto3

def invalidate_cloudfront(distribution_id, paths):
    """Invalidate CloudFront cache for specific paths"""
    client = boto3.client('cloudfront')
    
    response = client.create_invalidation(
        DistributionId=distribution_id,
        InvalidationBatch={
            'CallerReference': f'invalidation-{datetime.now().timestamp()}',
            'Paths': {
                'Quantity': len(paths),
                'Items': paths
            }
        }
    )
    
    return response['Invalidation']['Id']

# Usage
invalidate_cloudfront(
    'E1234567890ABC',
    [
        '/static/css/*.css',
        '/static/js/*.js',
        '/api/config'
    ]
)

Serverless at the Edge

Edge Function Platforms

Modern edge platforms let you run code closer to users:

Platform Edge Locations Language Support Cold Start
Cloudflare Workers 300+ JavaScript, Rust, Python, C++ <5ms
AWS Lambda@Edge 200+ Node.js, Python, Go, Java ~100ms
Vercel Edge 35+ JavaScript, TypeScript <10ms
Deno Deploy 40+ JavaScript, TypeScript <10ms

Cloudflare Workers Example

// Cloudflare Worker - Authentication at Edge
export default {
  async fetch(request, env) {
    // Parse JWT at edge
    const token = request.headers.get('Authorization')?.replace('Bearer ', '');
    
    if (!token) {
      return new Response('Unauthorized', { status: 401 });
    }
    
    try {
      // Verify JWT without round-trip to origin
      const payload = await verifyJWT(token, env.JWT_SECRET);
      
      // Add user context to headers
      const headers = new Headers(request.headers);
      headers.set('X-User-ID', payload.userId);
      headers.set('X-User-Role', payload.role);
      
      // Forward to origin with user context
      return fetch(request, { headers });
    } catch (e) {
      return new Response('Invalid token', { status: 403 });
    }
  }
}

async function verifyJWT(token, secret) {
  const parts = token.split('.');
  const header = JSON.parse(atob(parts[0]));
  const payload = JSON.parse(atob(parts[1]));
  const signature = parts[2];
  
  // In production, use a proper library
  // This is simplified for illustration
  return payload;
}

Lambda@Edge Examples

// Lambda@Edge - Request origin
exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  
  // Add security headers
  request.headers['x-edge-function'] = [{ key: 'x-edge-function', value: 'processed' }];
  
  // A/B testing at edge
  const cookies = parseCookies(request.headers['cookie']);
  
  if (!cookies.variant) {
    const variant = Math.random() > 0.5 ? 'a' : 'b';
    const response = {
      status: '302',
      headers: {
        'location': [{ key: 'location', value: request.uri }],
        'set-cookie': [
          { key: 'set-cookie', value: `variant=${variant}; Path=/; Max-Age=2592000` }
        ]
      }
    };
    callback(null, response);
    return;
  }
  
  // Forward request with variant header
  request.headers['x-variant'] = [{ key: 'x-variant', value: cookies.variant }];
  
  callback(null, request);
};

function parseCookies(cookieHeader) {
  if (!cookieHeader) return {};
  
  return cookieHeader.split(';').reduce((cookies, cookie) => {
    const [key, value] = cookie.trim().split('=');
    cookies[key] = value;
    return cookies;
  }, {});
}

Vercel Edge Functions

// Vercel Edge Function
import { NextRequest, NextResponse } from 'next/server';

export const config = {
  runtime: 'edge',
  regions: ['iad1', 'sfo1', 'fra1'], // Specify regions
};

export default async function handler(req: NextRequest) {
  const geo = req.geo;
  
  // Personalize based on user location
  const content = {
    city: geo?.city || 'Unknown',
    country: geo?.country || 'Unknown',
    region: geo?.region || 'Unknown',
    lat: geo?.latitude,
    lon: geo?.longitude,
  };
  
  // Fetch user-specific data from edge database
  const userData = await getUserData(req.headers.get('x-user-id'));
  
  return NextResponse.json({
    ...content,
    user: userData,
  });
}

async function getUserData(userId: string | null) {
  if (!userId) return null;
  
  // Use edge-compatible database (e.g., Turso, D1)
  const result = await fetch(
    `https://db.example.com/user/${userId}`,
    { cache: 'no-store' }
  );
  
  return result.json();
}

Edge Databases

Edge Database Options

Database Type Edge Replicas Latency Use Case
Cloudflare D1 SQLite 100+ <10ms Serverless apps
Turso SQLite 40+ <20ms Global apps
PlanetScale MySQL 50+ <50ms Full SQL
Fauna Document 10+ <100ms Flexible schema
Redis Enterprise KV 100+ <10ms Caching

Cloudflare D1 Example

-- D1 Database Schema
CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE posts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id INTEGER REFERENCES users(id),
  title TEXT NOT NULL,
  content TEXT,
  published_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_posts_user ON posts(user_id);
CREATE INDEX idx_posts_published ON posts(published_at DESC);
// Cloudflare Worker with D1
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const path = url.pathname;
    
    if (path === '/api/users' && request.method === 'GET') {
      const { results } = await env.DB.prepare(
        'SELECT * FROM users ORDER BY created_at DESC LIMIT 10'
      ).all();
      
      return Response.json(results);
    }
    
    if (path === '/api/users' && request.method === 'POST') {
      const { email, name } = await request.json();
      
      const { success } = await env.DB.prepare(
        'INSERT INTO users (email, name) VALUES (?, ?)'
      ).bind(email, name).run();
      
      return Response.json({ success });
    }
    
    return new Response('Not Found', { status: 404 });
  }
};

Global Architecture Patterns

Multi-Region Active-Active

# Terraform - Multi-region deployment
terraform {
  required_providers {
    aws = { source = "hashicorp/aws" }
  }
}

# Primary region
provider "aws" {
  alias  = "primary"
  region = "us-east-1"
}

# Secondary region
provider "aws" {
  alias  = "secondary"
  region = "us-west-2"
}

# Global DynamoDB
resource "aws_dynamodb_table" "global" {
  name           = "edge-app-global"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "pk"
  range_key      = "sk"
  
  attribute {
    name = "pk"
    type = "S"
  }
  
  attribute {
    name = "sk"
    type = "S"
  }
  
  replica {
    region_name = "us-east-1"
  }
  
  replica {
    region_name = "us-west-2"
  }
  
  server_side_encryption {
    enabled = true
  }
}

# CloudFront with multi-origin
resource "aws_cloudfront_distribution" "global" {
  enabled             = true
  price_class         = "PriceAll"
  comment             = "Global edge deployment"
  
  origin {
    domain_name = "primary.example.com"
    origin_id   = "primary"
    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "https-only"
      ssl_protocols          = ["TLSv1.2"]
    }
  }
  
  origin {
    domain_name = "secondary.example.com"
    origin_id   = "secondary"
    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "https-only"
      ssl_protocols          = ["TLSv1.2"]
    }
  }
  
  default_cache_behavior {
    target_origin_id       = "primary"
    viewer_protocol_policy = "redirect-to-https"
    
    # Use origin groups for failover
    origin_group_id        = aws_cloudfront_origin_group.primary.id
  }
  
  origin_group {
    id = "primary"
    members {
      origin_id = "primary"
    }
    failover_criteria {
      status_codes = [403, 404, 500, 502, 503, 504]
    }
  }
}

Edge-Based A/B Testing

// Edge A/B Testing with Cookie
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    
    // Check for existing variant
    let variant = getCookie(request, 'ab-variant');
    
    if (!variant) {
      // Assign new variant
      variant = Math.random() < 0.5 ? 'control' : 'treatment';
    }
    
    // Fetch experiment config from KV
    const experiment = await env.EXPERIMENTS.get(`experiment:${variant}`, 'json');
    
    // Add experiment headers for origin
    const response = await fetch(request);
    
    // Set cookie if not present
    if (!getCookie(request, 'ab-variant')) {
      const headers = new Headers(response.headers);
      headers.set('Set-Cookie', `ab-variant=${variant}; Path=/; Max-Age=2592000; SameSite=Lax`);
      
      return new Response(response.body, {
        status: response.status,
        headers
      });
    }
    
    return response;
  }
};

function getCookie(request, name) {
  const cookie = request.headers.get('Cookie');
  if (!cookie) return null;
  
  const match = cookie.match(new RegExp(`(${name})=([^;]+)`));
  return match ? match[2] : null;
}

Performance Optimization

Edge-Side Image Optimization

// Cloudflare Worker - Image resizing
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const imageUrl = url.searchParams.get('url');
    const width = url.searchParams.get('w') || '800';
    const format = url.searchParams.get('f') || 'webp';
    
    // Use Cloudflare Images
    const variants = await fetch(
      `https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/images/v1/variants/${format}`,
      {
        headers: {
          'Authorization': `Bearer ${env.CF_API_TOKEN}`
        }
      }
    ).then(r => r.json());
    
    // Redirect to resized image
    const imageId = imageUrl.split('/').pop();
    return Response.redirect(
      `https://imagedelivery.net/${env.CF_ACCOUNT_ID}/${imageId}/${format}?width=${width}`,
      302
    );
  }
};

Latency Optimization

# Predictive prefetching with Service Worker
// sw.js
const CACHE_NAME = 'edge-cache-v1';
const PREFETCH_URLS = ['/api/popular', '/api/config'];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(PREFETCH_URLS))
  );
});

self.addEventListener('fetch', event => {
  const url = new URL(event.request.url);
  
  // Prefetch likely navigation
  if (event.request.mode === 'navigate') {
    event.respondWith(
      fetch(event.request)
        .then(response => {
          const clone = response.clone();
          caches.open(CACHE_NAME)
            .then(cache => cache.put(event.request, clone));
          return response;
        })
        .catch(() => caches.match(event.request))
    );
  }
  
  // Stale-while-revalidate for API
  if (url.pathname.startsWith('/api/')) {
    event.respondWith(
      caches.open(CACHE_NAME)
        .then(cache => {
          const cached = cache.match(event.request);
          
          return fetch(event.request)
            .then(response => {
              cache.put(event.request, response.clone());
              return response;
            })
            .catch(() => cached);
        })
    );
  }
});

Monitoring Edge Performance

# Edge monitoring with Prometheus
groups:
  - name: edge
    rules:
      - alert: HighEdgeLatency
        expr: histogram_quantile(0.95, rate(cloudflare_edge_latency_bucket[5m])) > 0.5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High edge latency detected"
          
      - alert: CacheHitRateLow
        expr: (sum(rate(cloudflare_cache_hits[5m])) / sum(rate(cloudflare_cache_requests[5m]))) < 0.7
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Cache hit rate below 70%"
          
      - alert: EdgeErrors
        expr: sum(rate(cloudflare_errors[5m])) > 10
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Edge errors detected"

Cost Optimization

Edge computing can reduce costs significantly:

Optimization Potential Savings
Cache static assets 60-80% bandwidth
Edge compute vs origin 40-60% compute
Reduced data transfer 30-50% egress
Serverless edge 70-90% vs VMs
# Cost monitoring
resource "aws_cloudwatch_metric_alert" "cdncost" {
  alarm_name          = "cdn-cost-threshold"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods = 1
  metric_name         = "EstimatedCharges"
  namespace           = "AWS/Cost and Usage"
  period              = 86400
  statistic           = "Maximum"
  threshold           = 1000
  treat_missing_data  = "notBreaching"
  
  dimensions = {
    Service = "AmazonCloudFront"
  }
}

Conclusion

Edge computing transforms how we build global applications:

  • Use CDNs for all static content with proper cache headers
  • Deploy edge functions for personalization and authentication
  • Choose edge databases for globally distributed data
  • Implement multi-region active-active for critical applications
  • Monitor edge performance separately from origin

Start with CDN optimization, add edge functions for common use cases, then consider edge databases for global applications.

External Resources

Comments