Voltar para o Blog

Serverless e Edge Computing: Arquitetura de Baixa Latência que Domina 2025

Olá HaWkers, lembra quando deployar uma aplicação significava provisionar servidores, configurar balanceadores de carga, gerenciar escalabilidade manualmente e orar para que o tráfego não derrubasse tudo? Pois é, esses dias parecem cada vez mais distantes.

Em 2025, a combinação de serverless e edge computing transformou completamente como pensamos em infraestrutura. Hoje, você pode escrever uma função, dar deploy, e ela estará rodando em mais de 300 localidades ao redor do mundo, respondendo em menos de 50ms, escalando automaticamente de 0 a milhões de requisições - tudo sem você gerenciar um único servidor.

Parece mágica? Vamos desvendar como essa arquitetura funciona na prática.

Serverless: Além do Hype, A Realidade Prática

Serverless não significa "sem servidores" - significa que você não precisa se preocupar com servidores. A infraestrutura é abstraída, você paga apenas pelo que usa, e a escala acontece automaticamente.

O Modelo de Execução Serverless

Diferente de servidores tradicionais que ficam rodando 24/7, funções serverless são event-driven:

  1. Cold Start: Primeira invocação inicializa o ambiente de execução
  2. Warm: Execuções subsequentes reaproveitam o ambiente (se dentro da janela de tempo)
  3. Scaling: Múltiplas instâncias são criadas automaticamente sob demanda
  4. Billing: Você paga apenas pelo tempo de execução (milissegundos)

Quando Serverless Realmente Brilha

APIs com Tráfego Irregular: Se sua API tem picos de uso (e-commerce na Black Friday, por exemplo), serverless escala automaticamente.

Processamento de Eventos: Processamento de imagens, webhooks, jobs agendados - perfeitos para serverless.

Backends para JAMstack: Next.js, Nuxt, Remix - todos usam serverless functions para API routes.

Microserviços Leves: Cada função pode ser um microserviço independente, deployado separadamente.

Edge Computing: Levando Código Para Perto do Usuário

Edge computing leva serverless um passo além: em vez de rodar em uma região específica (us-east-1, por exemplo), seu código roda em data centers espalhados globalmente, próximos aos seus usuários.

Um usuário em São Paulo acessa o edge node brasileiro. Um usuário em Tóquio acessa o edge node japonês. Mesma aplicação, latência drasticamente reduzida.

A Diferença Entre Serverless Tradicional e Edge

AWS Lambda (Serverless Regional):

  • Executa em uma região específica (ex: us-east-1)
  • Cold start: 100-500ms
  • Latência adicional para usuários distantes

Cloudflare Workers (Edge Computing):

  • Executa em 300+ localidades globalmente
  • Cold start: <10ms
  • Latência consistentemente baixa globalmente

Casos de Uso Ideais Para Edge

Personalização de Conteúdo: Modificar HTML baseado em geolocalização, A/B testing, feature flags.

Autenticação e Autorização: Verificar tokens JWT antes de requests chegarem ao backend.

API Gateways: Roteamento inteligente, rate limiting, caching.

Middleware de Requisições: Headers, redirects, rewrite de URLs.

Cloudflare Workers: Edge Computing na Prática

Cloudflare Workers é a plataforma de edge computing mais popular em 2025. Vamos ver um exemplo prático:

Exemplo 1: API de Geolocalização com Cache Inteligente

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    // Informações de geolocalização disponíveis automaticamente
    const country = request.cf.country;
    const city = request.cf.city;
    const timezone = request.cf.timezone;

    // Cache key baseado em localização
    const cacheKey = `geo:${country}:${city}`;

    // Verificar cache no KV (key-value store do Cloudflare)
    let data = await env.GEO_CACHE.get(cacheKey, { type: 'json' });

    if (!data) {
      // Buscar dados customizados para essa localização
      data = await fetchLocationData(country, city);

      // Cachear por 1 hora
      await env.GEO_CACHE.put(cacheKey, JSON.stringify(data), {
        expirationTtl: 3600,
      });
    }

    return new Response(JSON.stringify({
      location: { country, city, timezone },
      data,
      cached: !!data,
    }), {
      headers: {
        'Content-Type': 'application/json',
        'Cache-Control': 'public, max-age=3600',
      },
    });
  },
};

async function fetchLocationData(country, city) {
  // Simular busca de dados personalizados
  return {
    currency: getCurrencyForCountry(country),
    language: getLanguageForCountry(country),
    popularProducts: await getPopularProducts(country),
    shippingOptions: await getShippingOptions(city),
  };
}

function getCurrencyForCountry(country) {
  const currencies = {
    BR: 'BRL',
    US: 'USD',
    JP: 'JPY',
    GB: 'GBP',
  };
  return currencies[country] || 'USD';
}

Este worker roda no edge mais próximo do usuário, detecta automaticamente a localização, e retorna dados personalizados com latência mínima.

Exemplo 2: Autenticação JWT no Edge

import { verify } from '@tsndr/cloudflare-worker-jwt';

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);

    // Rotas públicas não requerem auth
    const publicRoutes = ['/health', '/login', '/register'];
    if (publicRoutes.includes(url.pathname)) {
      return fetch(request);
    }

    // Extrair token do header
    const authHeader = request.headers.get('Authorization');
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      return new Response('Unauthorized', { status: 401 });
    }

    const token = authHeader.substring(7);

    try {
      // Verificar JWT no edge (sem chamar backend!)
      const isValid = await verify(token, env.JWT_SECRET);

      if (!isValid) {
        return new Response('Invalid token', { status: 401 });
      }

      // Decodificar payload para adicionar ao request
      const { payload } = jwt.decode(token);

      // Clonar request e adicionar user info nos headers
      const modifiedRequest = new Request(request);
      modifiedRequest.headers.set('X-User-Id', payload.userId);
      modifiedRequest.headers.set('X-User-Role', payload.role);

      // Encaminhar para origin
      return fetch(modifiedRequest);

    } catch (error) {
      return new Response('Token verification failed', { status: 401 });
    }
  },
};

Essa abordagem verifica autenticação no edge, antes da requisição chegar ao seu backend, economizando latência e carga nos servidores.

AWS Lambda@Edge: Serverless na CDN da Amazon

AWS Lambda@Edge permite rodar funções Lambda nos edge locations do CloudFront (200+ localizações).

Exemplo: Redirecionamento Inteligente Baseado em Device

// Lambda@Edge para CloudFront
exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;

  // Detectar tipo de device
  const userAgent = headers['user-agent']?.[0]?.value || '';
  const isMobile = /mobile|android|iphone/i.test(userAgent);
  const isTablet = /tablet|ipad/i.test(userAgent);

  // Redirecionar para versões otimizadas
  if (request.uri === '/') {
    if (isMobile) {
      return {
        status: '302',
        statusDescription: 'Found',
        headers: {
          location: [{
            key: 'Location',
            value: '/mobile',
          }],
        },
      };
    }

    if (isTablet) {
      return {
        status: '302',
        statusDescription: 'Found',
        headers: {
          location: [{
            key: 'Location',
            value: '/tablet',
          }],
        },
      };
    }
  }

  // Modificar headers para otimização
  request.headers['x-device-type'] = [{
    key: 'X-Device-Type',
    value: isMobile ? 'mobile' : isTablet ? 'tablet' : 'desktop',
  }];

  return request;
};

Exemplo: Geração de Imagens Responsivas no Edge

const sharp = require('sharp');
const AWS = require('aws-sdk');
const s3 = new AWS.S3();

exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const response = event.Records[0].cf.response;

  // Extrair parâmetros de query
  const params = new URLSearchParams(request.querystring);
  const width = parseInt(params.get('w') || '800');
  const quality = parseInt(params.get('q') || '80');
  const format = params.get('f') || 'webp';

  // Buscar imagem original do S3
  const s3Object = await s3.getObject({
    Bucket: 'my-images-bucket',
    Key: request.uri.substring(1), // remove leading /
  }).promise();

  // Processar imagem com Sharp
  const processedImage = await sharp(s3Object.Body)
    .resize(width, null, { withoutEnlargement: true })
    .toFormat(format, { quality })
    .toBuffer();

  // Retornar imagem processada
  return {
    status: '200',
    statusDescription: 'OK',
    headers: {
      'content-type': [{
        key: 'Content-Type',
        value: `image/${format}`,
      }],
      'cache-control': [{
        key: 'Cache-Control',
        value: 'public, max-age=31536000, immutable',
      }],
    },
    body: processedImage.toString('base64'),
    bodyEncoding: 'base64',
  };
};

Vercel Edge Functions: Next.js no Edge

Vercel Edge Functions são otimizadas para Next.js e rodam no edge globalmente.

Exemplo: A/B Testing no Edge

// app/middleware.js
import { NextResponse } from 'next/server';

export function middleware(request) {
  // Bucket aleatório para A/B test (0-99)
  const bucket = Math.floor(Math.random() * 100);

  // 50% dos usuários veem variante A, 50% veem B
  const variant = bucket < 50 ? 'A' : 'B';

  // Clonar response para adicionar cookie
  const response = NextResponse.next();

  // Armazenar variante no cookie (persistência entre páginas)
  response.cookies.set('ab-test-variant', variant, {
    maxAge: 60 * 60 * 24 * 30, // 30 dias
  });

  // Adicionar header para analytics
  response.headers.set('X-AB-Test-Variant', variant);

  // Rewrite baseado na variante
  if (request.nextUrl.pathname === '/pricing') {
    if (variant === 'B') {
      return NextResponse.rewrite(new URL('/pricing-variant-b', request.url));
    }
  }

  return response;
}

export const config = {
  matcher: ['/pricing', '/checkout'],
};

Exemplo: Rate Limiting no Edge

import { NextResponse } from 'next/server';

const rateLimit = new Map();

export function middleware(request) {
  const ip = request.ip || 'unknown';
  const now = Date.now();
  const windowMs = 60 * 1000; // 1 minuto
  const maxRequests = 100;

  // Limpar entradas antigas
  for (const [key, value] of rateLimit.entries()) {
    if (now - value.timestamp > windowMs) {
      rateLimit.delete(key);
    }
  }

  // Verificar rate limit
  const userLimit = rateLimit.get(ip);

  if (!userLimit) {
    rateLimit.set(ip, { count: 1, timestamp: now });
  } else if (now - userLimit.timestamp > windowMs) {
    // Resetar janela
    rateLimit.set(ip, { count: 1, timestamp: now });
  } else if (userLimit.count >= maxRequests) {
    // Limite excedido
    return new NextResponse('Rate limit exceeded', {
      status: 429,
      headers: {
        'Retry-After': String(Math.ceil((windowMs - (now - userLimit.timestamp)) / 1000)),
      },
    });
  } else {
    // Incrementar contador
    userLimit.count++;
  }

  return NextResponse.next();
}

Padrões de Arquitetura Serverless Moderna

1. Backend for Frontend (BFF) Pattern

// Cloudflare Worker atuando como BFF
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // Diferentes backends para diferentes clients
    if (url.pathname.startsWith('/api/mobile')) {
      // Mobile recebe dados otimizados (menos campos)
      const data = await fetchFromBackend(env.MOBILE_API);
      return new Response(JSON.stringify({
        ...data,
        _optimized: true,
      }));
    }

    if (url.pathname.startsWith('/api/web')) {
      // Web recebe dados completos
      const data = await fetchFromBackend(env.WEB_API);
      return new Response(JSON.stringify(data));
    }

    return new Response('Not Found', { status: 404 });
  },
};

2. Event-Driven Serverless

// AWS Lambda triggered por S3 upload
exports.handler = async (event) => {
  const s3Event = event.Records[0].s3;
  const bucket = s3Event.bucket.name;
  const key = s3Event.object.key;

  console.log(`Processing file: ${key} from bucket: ${bucket}`);

  // Processar imagem
  const originalImage = await s3.getObject({ Bucket: bucket, Key: key }).promise();

  // Gerar thumbnails em paralelo
  const thumbnails = await Promise.all([
    generateThumbnail(originalImage, 200, 200),
    generateThumbnail(originalImage, 400, 400),
    generateThumbnail(originalImage, 800, 800),
  ]);

  // Upload thumbnails para S3
  await Promise.all(thumbnails.map((thumb, i) =>
    s3.putObject({
      Bucket: `${bucket}-thumbnails`,
      Key: `${key}-${[200, 400, 800][i]}px`,
      Body: thumb,
      ContentType: 'image/jpeg',
    }).promise()
  ));

  return { statusCode: 200, body: 'Thumbnails generated' };
};

3. Caching Estratégico no Edge

export default {
  async fetch(request, env, ctx) {
    const cache = caches.default;
    const cacheKey = new Request(request.url, request);

    // Verificar cache primeiro
    let response = await cache.match(cacheKey);

    if (!response) {
      // Cache miss - buscar do backend
      response = await fetch(request);

      // Cachear se status for 200
      if (response.status === 200) {
        // Clonar response para cachear (pode ser consumida apenas 1x)
        const responseToCache = response.clone();

        // Adicionar ao cache (assíncrono via waitUntil)
        ctx.waitUntil(cache.put(cacheKey, responseToCache));
      }
    }

    return response;
  },
};

Desafios e Considerações Práticas

Cold Starts: O Calcanhar de Aquiles

Funções serverless sofrem de "cold starts" quando ficam inativas. Estratégias para mitigar:

1. Keep-Alive Pings: Invocar funções periodicamente para mantê-las warm
2. Provisioned Concurrency (AWS): Manter instâncias sempre warm (custo adicional)
3. Edge Computing: Workers têm cold starts drasticamente menores (<10ms)

Limites de Execução

AWS Lambda: 15 minutos máximo
Cloudflare Workers: 50ms CPU time (plano free), 50ms-30s (plano pago)
Vercel Edge: 30 segundos

Para processamentos longos, considere split em múltiplas funções ou usar Step Functions.

Monitoramento e Debugging

Serverless dificulta debugging tradicional. Use:

  • Structured Logging: JSON logs para fácil parsing
  • Distributed Tracing: AWS X-Ray, Datadog, Sentry
  • Metrics: CloudWatch, Prometheus para monitorar latência e erros

O Futuro: Edge-First Architecture

Em 2025, a tendência é clara: edge-first. Aplicações modernas estão sendo desenhadas desde o início para rodar no edge, aproveitando:

  • Baixa latência global: Usuários no Brasil e Japão têm a mesma experiência
  • Escalabilidade automática: De 0 a milhões sem configuração
  • Custo otimizado: Pague apenas pelo que usa
  • Resiliência: Distribuído globalmente, sem single point of failure

Se você está construindo aplicações web modernas, serverless e edge computing não são mais "nice to have" - são essenciais para competir em performance e experiência do usuário.

Se você se sente inspirado pelo poder do serverless e edge computing, recomendo que dê uma olhada em outro artigo: Microfrontends: Arquitetura Modular onde você vai descobrir como combinar edge computing com arquitetura de microfrontends para criar aplicações verdadeiramente escaláveis.

Bora pra cima! 🦅

📚 Quer Aprofundar Seus Conhecimentos em JavaScript?

Este artigo cobriu serverless e edge computing, mas há muito mais para explorar no mundo do desenvolvimento moderno.

Desenvolvedores que investem em conhecimento sólido e estruturado tendem a ter mais oportunidades no mercado.

Material de Estudo Completo

Se você quer dominar JavaScript do básico ao avançado, preparei um guia completo:

Opções de investimento:

  • R$9,90 (pagamento único)

👉 Conhecer o Guia JavaScript

💡 Material atualizado com as melhores práticas do mercado

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário