Serverless: funções como serviço e seus trade-offs

1. Introdução ao Serverless e FaaS

No contexto da Arquitetura de Software, o termo Serverless não significa ausência de servidores, mas sim a abstração completa do gerenciamento de infraestrutura. O desenvolvedor se concentra exclusivamente no código da aplicação, enquanto o provedor de nuvem provisiona, escala e mantém os servidores automaticamente.

Functions as a Service (FaaS) é a materialização mais pura desse paradigma. Diferentemente do PaaS (Platform as a Service), onde você gerencia o ambiente de execução da aplicação, e do IaaS (Infrastructure as a Service), onde gerencia máquinas virtuais, no FaaS você envia funções individuais que são executadas sob demanda. Cada função é um bloco de código autônomo, stateless e efêmero.

Os principais provedores incluem:
- AWS Lambda: pioneiro, integração profunda com ecossistema AWS
- Azure Functions: forte integração com serviços Microsoft
- Google Cloud Functions: foco em simplicidade e integração com GCP

2. Modelo de Execução e Ciclo de Vida

No FaaS, a execução é orientada a eventos. Quando um acionador ocorre, o provedor aloca um contêiner, carrega o runtime e executa a função. Esse processo revela dois estados críticos:

  • Cold start: ocorre quando um novo contêiner precisa ser iniciado. Pode adicionar latência de 100ms a vários segundos, dependendo do runtime e do tamanho do pacote.
  • Warm start: quando o contêiner já está ativo e reutilizado para invocações subsequentes, reduzindo drasticamente a latência.

Exemplo de função simples em Node.js:

exports.handler = async (event) => {
    const name = event.queryStringParameters?.name || 'Mundo';
    return {
        statusCode: 200,
        body: `Olá, ${name}!`
    };
};

Limitações importantes:
- Tempo máximo de execução: tipicamente 15 minutos (AWS Lambda)
- Memória: de 128 MB a 10 GB
- Armazenamento temporário: /tmp limitado a 512 MB a 10 GB

3. Arquitetura Orientada a Eventos no Serverless

A natureza event-driven do FaaS permite padrões arquiteturais poderosos:

Acionadores comuns:
- HTTP (API Gateway)
- Filas (SQS, RabbitMQ)
- Bancos de dados (DynamoDB Streams, CDC)
- Storage (S3 uploads)

Padrões de composição:

Fan-out (processamento paralelo):

Função A recebe evento -> publica 100 mensagens no SQS
Função B processa cada mensagem independentemente

Fan-in (agregação de resultados):

Múltiplas funções gravam resultados parciais no DynamoDB
Função C é acionada quando todos os resultados estão prontos

Para orquestração complexa, serviços como AWS Step Functions ou Azure Durable Functions são recomendados, pois evitam acoplamento excessivo entre funções.

4. Trade-offs de Desempenho e Latência

O cold start é o principal vilão do desempenho em FaaS. Seu impacto varia:

  • Runtimes: Java e .NET sofrem mais (500ms-5s); Python e Node.js são mais rápidos (100ms-1s)
  • Tamanho do pacote: bibliotecas pesadas aumentam o tempo de carregamento
  • VPC: funções dentro de VPC têm cold starts mais longos devido à alocação de ENI

Estratégias de mitigação:

  1. Provisioned Concurrency (AWS): mantém N instâncias sempre aquecidas
  2. Warmers: funções heartbeat que invocam a função periodicamente
  3. Redução de dependências: minimize bibliotecas e use layers otimizados

Throttling: provedores impõem limites de concorrência (ex: 1000 execuções simultâneas por região no Lambda). Exceder resulta em erros 429.

5. Gerenciamento de Estado e Dados

Funções são inerentemente stateless – cada invocação é isolada. Estado compartilhado exige serviços externos:

Padrões de armazenamento:
- DynamoDB: baixa latência, escalável, ideal para sessões
- Redis (ElastiCache): cache distribuído para dados temporários
- S3: armazenamento de objetos para arquivos grandes

Exemplo de função com estado externo:

const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {
    const params = {
        TableName: 'sessions',
        Key: { sessionId: event.sessionId }
    };
    const result = await dynamo.get(params).promise();
    return { statusCode: 200, body: JSON.stringify(result.Item) };
};

Desafios: transações distribuídas e consistência eventual exigem padrões como Saga ou compensação manual.

6. Custos e Modelos de Precificação

O modelo pay-per-use é a maior vantagem do FaaS para cargas esporádicas. Você paga por:
- Número de requisições
- Tempo de execução (arredondado para 100ms)
- Memória alocada

Custos ocultos:
- Cold starts: invocações extras para manter funções aquecidas
- Transferência de dados entre regiões
- Logs no CloudWatch (retenção e volume)
- API Gateway (custo por requisição)

Comparação TCO:
- Para workloads previsíveis (ex: 24/7), instâncias reservadas ou contêineres podem ser 40-60% mais baratos
- Para cargas variáveis (ex: picos sazonais), FaaS reduz drasticamente o custo

7. Observabilidade e Depuração

Ambientes efêmeros dificultam debugging tradicional. Ferramentas essenciais:

  • CloudWatch Logs: logs centralizados, mas sem contexto de execução
  • AWS X-Ray: tracing distribuído, identifica gargalos entre funções
  • OpenTelemetry: padrão aberto para instrumentação multi-provedor

Estratégias de teste:
- Testes locais com ferramentas como SAM CLI (AWS) ou Functions Framework (Google)
- Ambientes de staging idênticos à produção
- Logs estruturados em JSON para facilitar consultas

8. Quando Usar (e Quando Evitar) Serverless

Casos de uso ideais:
- Webhooks e processamento de eventos assíncronos
- APIs com tráfego variável (ex: CRUD leve)
- Processamento de streams (Kinesis, Kafka)
- Transformação de dados em pipelines ETL
- Tarefas agendadas (cron jobs)

Anti-padrões:
- Jobs de longa duração (>15 minutos)
- Workloads intensivos em CPU (processamento de vídeo, ML training)
- Aplicações com estado de conexão persistente (WebSockets)
- Sistemas que exigem latência consistente <10ms

Decisão arquitetural: a abordagem mais madura é combinar Serverless com microsserviços tradicionais. Use FaaS para componentes event-driven e escaláveis, enquanto mantém serviços stateful ou de longa duração em contêineres ou VMs.

Conclusão

Serverless e FaaS representam uma evolução significativa na Arquitetura de Software, oferecendo escalabilidade automática e redução de custos operacionais. No entanto, os trade-offs de latência, estado e observabilidade exigem análise cuidadosa. O sucesso depende de alinhar o padrão arquitetural ao tipo de workload, combinando diferentes abordagens quando necessário.

Referências