ADR-002: Arquitetura de Persistência de Dados - Anomalias de Custo
Status: Proposto
Data: 16/10/2025
Contexto: Módulo de Anomalias de Custos AWS - Persistência de dados
Decisores: Equipe FinOps
1. Contexto e Problema
O módulo de Anomalias de Custos atualmente processa dados diretamente da AWS Cost Explorer API através de uma Lambda (new_anomaly_processor.py), mas não persiste essas informações em banco de dados. Isso limita:
- Histórico e Auditoria: Não há registro histórico das anomalias processadas
- Performance: Cada requisição demanda chamadas à API AWS, aumentando latência
- Funcionalidades: Impossibilita features como justificativas, feedback persistente e análises históricas
- Custos: Chamadas repetidas à API AWS aumentam custos operacionais
Objetivo: Definir e documentar a arquitetura de persistência de dados que permita armazenamento, recuperação e gerenciamento eficiente das anomalias de custo.
2. Decisão Arquitetural
2.1 Processo Escolhido
Implementaremos uma arquitetura de persistência baseada em PostgreSQL com camada de API RESTful através de AWS Lambda + API Gateway, seguindo o padrão BFF (Backend for Frontend).
Fluxo de dados:
AWS Cost Explorer API
↓
Lambda Processor (new_anomaly_processor.py)
↓
PostgreSQL (RDS)
↓
Lambda Endpoints (API Gateway)
↓
Frontend (Dashboard)
Características principais:
- Persistência Relacional: PostgreSQL hospedado em AWS RDS para garantir integridade referencial
- Processamento Assíncrono: Lambda para processamento batch dos dados AWS
- API RESTful: Endpoints dedicados para operações CRUD
- Atualização Programada: EventBridge/CloudWatch Events para execução periódica
- Retenção Inteligente: Política de 90 dias com exceção para anomalias justificadas
3. Modelo de Banco de Dados
3.1 Estrutura de Tabelas
Tabela: tb_cost_anomalies
Armazena as anomalias de custo detectadas pela AWS.
Tabela: tb_root_causes
Armazena as causas raiz de cada anomalia.
3.2 Diagrama Entidade-Relacionamento (ERD)

Figura: Diagrama Entidade-Relacionamento (ERD) das tabelas tb_cost_anomalies e tb_root_causes.
3.3 Organização das Queries e Metas
Alteração: O uso de SQLAlchemy foi removido. As queries SQL são realizadas diretamente via comandos SQL brutos (raw SQL) utilizando o driver padrão do Python para PostgreSQL (
psycopg2ou similar). A organização das metas e operações (inserção, atualização, deleção) é feita por funções utilitárias Python, que executam as queries conforme a necessidade de cada endpoint, garantindo atomicidade via transações explícitas.
Exemplo de operação (pseudo-código):
def update_anomaly_feedback(conn, anomaly_id, feedback, justification, justified_by):
with conn.cursor() as cur:
cur.execute(
'''
UPDATE tb_cost_anomalies
SET feedback = %s, justification = %s, justified_by = %s, updated_at = NOW()
WHERE anomaly_id = %s
''',
(feedback, justification, justified_by, anomaly_id)
)
conn.commit()
4. Arquitetura de Processamento
4.1 Visão Geral
A arquitetura utilizará múltiplas AWS Lambdas, cada uma responsável por uma operação específica (CRUD), expostas através de API Gateway com endpoints RESTful.
Componentes:
-
Lambda de Processamento (Existente):
new_anomaly_processor.py -
Busca dados da AWS Cost Explorer API
- Persiste/atualiza dados no PostgreSQL
-
Executada via EventBridge (agendamento)
-
Lambda de API (Novos): Endpoints para consulta e atualização
- Operações GET, PUT para frontend
- Validação e transformação de dados
- Expostos via API Gateway
4.2 Repositório
Repositório: plat-eng-finop-cloud-cost-anomalies-engine
Regras de Negócio:
- Se
feedbackfor alterado, sincronizar com AWS Cost Explorer via APIupdate_anomaly_feedback() - Atualizar
updated_attimestamp - Registrar auditoria da alteração
4.3 Configuração do API Gateway
- API Gateway REST API com endpoints HTTP para cada Lambda.
- API Keys obrigatórias para acesso aos endpoints privados.
- Uso de Usage Plans para controle de quota e throttling.
- Integração com WAF para proteção contra ataques.
- CORS configurado conforme necessidade de cada rota.
- Desabilitação do endpoint default do API Gateway para evitar exposição desnecessária.
- Rotas privadas (private: true) para endpoints sensíveis.
Exemplo de configuração (trecho do serverless.yml):
provider:
apiGateway:
apiKeys:
- name: ${self:service}-${self:provider.stage}-api-key
enabled: true
apiKeySourceType: HEADER
disableDefaultEndpoint: true
usagePlan:
quota:
limit: 10000
period: DAY
throttle:
burstLimit: 200
rateLimit: 100
logs:
restApi:
accessLogging: false
executionLogging: true
tracing:
apiGateway: true
custom:
customDomain:
enabled: true
domainName: ${self:service}.${self:provider.stage}.${env:VS}.grupoboticario.digital
stage: ${self:provider.stage}
basePath: ""
createRoute53Record: false
associateWaf:
name: acl-backend
version: V2
Variáveis de Ambiente Necessárias:
PG_HOST: Host do banco PostgreSQLPG_PORT: Porta do banco PostgreSQLPG_USER: Usuário do bancoPG_PASSWORD: Senha do bancoPG_DATABASE: Nome do bancoROLE_ARN: ARN do papel para assumir permissões AWSAWS_ACCOUNT_ID,VS,NEWRELIC_ACCOUNT_ID,NEWRELIC_API_KEY, etc. (conforme já utilizado no projeto)
4.4 Uso de Custom Domain
- O domínio da API é customizado, ficou definido o padrão:
https://cloud-cost-anomalies-engine.hml.platform-engineering.grupoboticario.digital - O domínio é configurado via plugin
serverless-domain-managere não cria registros Route53 automaticamente (createRoute53Record: false). - Permite padronização de acesso e integração segura com o frontend.
4.4 Regras de Atualização e Retenção de Dados
Política de Sincronização:
-
Frequência de Atualização:
-
Lambda
new_anomaly_processorexecutado uma vez ao dia via EventBridge - Busca anomalias dos últimos 90 dias da AWS Cost Explorer API
-
Período de 90 dias alinhado com a retenção padrão da AWS
-
Estratégia de Upsert:
-
Utilizar
anomaly_idcomo chave de identificação única - Se anomalia já existe: UPDATE (atualizar valores atuais)
- Se anomalia é nova: INSERT (criar novo registro)
-
Root Causes: DELETE + INSERT para cada anomalia (cascata)
-
Retenção de Dados:
-
Regra Geral: Anomalias com mais de 90 dias são removidas do banco
-
Exceção: Anomalias com
justification_id != NULLsão mantidas permanentemente -
Lógica de Cleanup:
DELETE FROM tb_cost_anomalies WHERE anomaly_start_date < (CURRENT_DATE - INTERVAL '90 days') AND justification_id IS NULL; -
Sincronização de Feedback com AWS:
-
Quando usuário altera
feedbackvia PUT endpoint - Lambda chama
update_anomaly_feedback()da AWS Cost Explorer API - Mantém consistência entre banco local e AWS
- Em caso de falha: registrar em fila de retry (SQS)
Diagrama de Fluxo de Atualização:
┌─────────────────────────────────────────────────┐
│ EventBridge (diário) │
└────────────────┬────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Lambda: new_anomaly_processor │
│ ├─ Buscar últimos 90 dias da AWS API │
│ ├─ Processar anomalias e root causes │
│ └─ Upsert no PostgreSQL │
└────────────────┬────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ PostgreSQL RDS │
│ ├─ tb_cost_anomalies │
│ ├─ tb_root_causes │
└────────────────┬────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Lambda: Cleanup Job (diário) │
│ └─ Remove anomalias > 90 dias sem justif. │
└─────────────────────────────────────────────────┘
5. Visualizações do Usuário (Dashboard)
5.1 Endpoints Utilizados
- Cards de Métricas:
GET /cards- Gráficos de Evolução:
GET /graph- Tabela de Anomalias:
GET /table/detected-anomalies- Tabela de Causas Raiz:
GET /table/anomalies-root-causes- Anomalias por Feedback:
GET /anomaly-by-feedback- Atualização de Justificativa:
PUT /update-justification- Atualização de Feedback:
PUT /update-feedback
5.2 Ações Disponíveis
- Visualização de métricas agregadas (cards)
- Visualização de gráficos de tendência e impacto
- Consulta detalhada de anomalias e causas raiz
- Filtros por feedback, conta, período, etc.
- Edição de justificativa e feedback diretamente pela interface
6. Referências
- AWS Cost Explorer API Documentation
- Serverless Framework Documentation
- SQLAlchemy ORM Documentation
- AWS Lambda Best Practices
- PostgreSQL Performance Tuning
Última Atualização: 31/10/2025
Versão: 1.1
Autor: Gabriel Pepe, Fabio Batimarco