# Escalabilidade

Estrategia de escalabilidade horizontal e vertical para a plataforma FluxiQ PIX, incluindo tuning de workers, load testing com K6 e planejamento de capacidade.

## Pre-requisitos

- Cluster Kubernetes com HPA (Horizontal Pod Autoscaler) configurado
- Metrics Server instalado no cluster
- Ferramenta K6 instalada para testes de carga
- Acesso ao Grafana/Prometheus para monitoramento de metricas
- Conhecimento basico de NATS JetStream consumers

## Visao Geral da Arquitetura de Escalabilidade

```mermaid
graph TB
    subgraph Ingress
        LB[Load Balancer<br/>Traefik]
    end

    subgraph Backend Pods
        POD1[pix-backend-1<br/>4 apps Elixir]
        POD2[pix-backend-2<br/>4 apps Elixir]
        PODN[pix-backend-N<br/>4 apps Elixir]
    end

    subgraph Database
        PG_PRIMARY[(PostgreSQL<br/>Primary)]
        PG_READ1[(Read Replica 1)]
        PG_READ2[(Read Replica 2)]
    end

    subgraph Redis
        R_M1[Redis Master 1]
        R_M2[Redis Master 2]
        R_M3[Redis Master 3]
        R_S1[Redis Slave 1]
        R_S2[Redis Slave 2]
        R_S3[Redis Slave 3]
    end

    subgraph NATS
        N1[NATS Node 1]
        N2[NATS Node 2]
        N3[NATS Node 3]
    end

    LB --> POD1
    LB --> POD2
    LB --> PODN

    POD1 --> PG_PRIMARY
    POD1 -.-> PG_READ1
    POD2 --> PG_PRIMARY
    POD2 -.-> PG_READ2

    POD1 --> R_M1
    POD2 --> R_M2

    POD1 <--> N1
    POD2 <--> N2
    PODN <--> N3

    R_M1 --> R_S1
    R_M2 --> R_S2
    R_M3 --> R_S3
```

## Escalabilidade do Backend

### Horizontal Pod Autoscaler (HPA)

Configuracao HPA para escalar pods baseado em CPU e memoria:

```yaml
# deploy/hpa-backend.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: pix-backend-hpa
  namespace: pix
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: pix-backend
  minReplicas: 2
  maxReplicas: 8
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Pods
          value: 2
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Pods
          value: 1
          periodSeconds: 120
```

Aplicar e verificar:

```bash
kubectl apply -f deploy/hpa-backend.yaml

# Verificar HPA
kubectl get hpa -n pix
# Saida esperada:
# NAME                REFERENCE             TARGETS           MINPODS   MAXPODS   REPLICAS
# pix-backend-hpa     Deployment/pix-backend   45%/70%, 52%/80%   2         8         2
```

### Escalar Manualmente

```bash
# Aumentar replicas para 4 pods
kubectl scale deployment/pix-backend -n pix --replicas=4

# Verificar status
kubectl get pods -n pix -l app=pix-backend
# Saida esperada:
# NAME                           READY   STATUS    RESTARTS   AGE
# pix-backend-7b8f9d6c4-abc12   1/1     Running   0          5m
# pix-backend-7b8f9d6c4-def34   1/1     Running   0          5m
# pix-backend-7b8f9d6c4-ghi56   1/1     Running   0          30s
# pix-backend-7b8f9d6c4-jkl78   1/1     Running   0          30s
```

### Recursos por Pod

Configuracao atual de recursos (deploy/backend.yaml):

| Recurso | Request | Limit |
|---------|---------|-------|
| CPU | 2 cores | 4 cores |
| Memoria | 2 GiB | 4 GiB |

Recomendacao por faixa de TPS:

| TPS Alvo | Pods | CPU/Pod | Memoria/Pod | Total CPU | Total Memoria |
|----------|------|---------|-------------|-----------|---------------|
| 500 | 2 | 2 cores | 2 GiB | 4 cores | 4 GiB |
| 1.000 | 3 | 2 cores | 3 GiB | 6 cores | 9 GiB |
| 2.500 | 4 | 3 cores | 4 GiB | 12 cores | 16 GiB |
| 5.000 | 6 | 4 cores | 4 GiB | 24 cores | 24 GiB |
| 7.500 | 8 | 4 cores | 6 GiB | 32 cores | 48 GiB |

## Escalabilidade do Banco de Dados

### Connection Pooling

A formula de conexoes totais:

```
Total de conexoes = POOL_SIZE x numero_de_repos x numero_de_pods
```

Configuracao atual:

| Parametro | Valor | Calculo |
|-----------|-------|---------|
| POOL_SIZE | 200 | Por repo |
| Repos | 4 | Shared, Dict, SPI, Settlement |
| Pods | 2 | Padrao |
| **Total** | **1.600** | 200 x 4 x 2 |

Para escalar a 8 pods:

```
200 x 4 x 8 = 6.400 conexoes
```

::: warning Limites do PostgreSQL
O `max_connections` atual e 6.000. Para mais de 6 pods, considere:
1. Reduzir POOL_SIZE para 150 (150 x 4 x 8 = 4.800)
2. Usar PgBouncer como connection pooler externo
3. Aumentar max_connections (requer mais memoria)
:::

Ajustar POOL_SIZE via variavel de ambiente:

```yaml
# deploy/backend.yaml
env:
  - name: POOL_SIZE
    value: "150"  # Reduzido para suportar mais pods
```

### Read Replicas

Para cargas de leitura intensiva, configurar replicas de leitura:

```bash
# Criar read replica no GCP
gcloud sql instances create pix-read-replica-1 \
  --master-instance-name=pix-primary \
  --region=southamerica-east1 \
  --tier=db-custom-4-16384

# Obter IP da replica
gcloud sql instances describe pix-read-replica-1 \
  --format='get(ipAddresses[0].ipAddress)'
```

Configurar Ecto para usar replica de leitura:

```elixir
# config/runtime.exs
config :shared, Shared.ReadRepo,
  url: System.get_env("DATABASE_READ_URL"),
  pool_size: String.to_integer(System.get_env("READ_POOL_SIZE", "100"))
```

## Escalabilidade Redis

### Modo Cluster (3 Masters + 3 Slaves)

Para alta disponibilidade e throughput:

```bash
# Criar cluster Redis com 6 nos
redis-cli --cluster create \
  10.140.240.4:6379 \
  10.140.240.5:6379 \
  10.140.240.6:6379 \
  10.140.240.7:6379 \
  10.140.240.8:6379 \
  10.140.240.9:6379 \
  --cluster-replicas 1

# Verificar cluster
redis-cli -h 10.140.240.4 -p 6379 CLUSTER INFO
# Saida esperada:
# cluster_enabled:1
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_known_nodes:6
# cluster_size:3
```

### Dados Armazenados no Redis

| Tipo de Dado | Padrao de Chave | TTL | Volume Estimado |
|-------------|----------------|-----|-----------------|
| Token blacklist | `blacklist:{jti}` | Remaining JWT TTL | ~1K chaves |
| Rate limiting | `rate_limit:{ip}:{path}` | 15 min | ~10K chaves |
| Idempotency | `idempotency:{user_id}:{key}` | 24h | ~50K chaves |
| RBAC cache | `rbac:{group_id}` | 5 min (ETS) | Em ETS, nao Redis |
| Session cache | `session:{session_id}` | 24h | ~5K chaves |

## Escalabilidade NATS JetStream

### Cluster (Minimo 3 Nos)

Configuracao atual: 3 nos em VMs dedicadas:

| No | IP | Porta |
|----|-----|-------|
| nats-dev-1 | 10.10.40.5 | 4222 |
| nats-dev-2 | 10.10.40.7 | 4222 |
| nats-dev-3 | 10.10.40.4 | 4222 |

Para aumentar replicas das streams (maior durabilidade):

```bash
# Atualizar stream para 3 replicas (requer 3+ nos)
nats stream edit MONETARIE_SPI \
  --replicas=3 \
  --server=nats://10.10.40.5:4222

# Verificar
nats stream info MONETARIE_SPI --server=nats://10.10.40.5:4222 | grep Replicas
# Saida esperada: Replicas: 3
```

## Escalabilidade dos Workers

### Configuracao dos Workers

Cada worker tem parametros configuraveis que afetam throughput:

| Worker | Stream | batch_size | max_concurrency | poll_interval |
|--------|--------|------------|-----------------|---------------|
| InboundProcessor | MONETARIE_SPI | 100 | 10 | 200ms |
| OutboundSender | MONETARIE_SPI | 100 | 10 | 200ms |
| StatusUpdater | MONETARIE_SPI | 100 | 10 | 200ms |
| ReturnProcessor | MONETARIE_SPI | 100 | 5 | 200ms |
| CoreEventProcessor | MONETARIE_CORE | 50 | 5 | 500ms |
| Scheduler | MONETARIE_SETTLEMENT | 10 | 1 | 5000ms |
| FileImporter | MONETARIE_SETTLEMENT | 10 | 1 | 10000ms |

### Throughput Teorico por Worker

```
TPS_worker = batch_size x max_concurrency / avg_processing_time_seconds
```

Exemplo para InboundProcessor:

```
TPS = 100 x 10 / 0.05 = 20.000 mensagens/segundo (teorico)
TPS = 100 x 10 / 0.5  = 2.000 mensagens/segundo (com I/O DB)
```

### Backpressure Adaptativo

O BaseWorker ajusta automaticamente o intervalo de polling baseado na carga:

| Situacao | Batch Recebido | Poll Interval | Efeito |
|----------|---------------|---------------|--------|
| Fila cheia | `= batch_size` | `min_poll_interval` (50ms) | Polling agressivo |
| Fila parcial | `< batch_size` | `poll_interval` (200ms) | Polling normal |
| Fila vazia | `= 0` | `max_poll_interval` (2000ms) | Polling conservador |

Para ajustar os parametros de backpressure, modifique a definicao `use` do worker:

```elixir
# Exemplo: aumentar throughput do InboundProcessor
use Shared.Workers.BaseWorker,
  stream: "MONETARIE_SPI",
  consumer: "inbound-processor",
  filter_subject: "monetarie.spi.transaction.created",
  poll_interval: 100,          # 100ms (era 200ms)
  batch_size: 200,             # 200 msgs (era 100)
  max_concurrency: 20,         # 20 tasks (era 10)
  min_poll_interval: 25,       # 25ms (era 50ms)
  max_poll_interval: 1_000     # 1s (era 2s)
```

::: warning Impacto no banco de dados
Aumentar `batch_size` e `max_concurrency` gera mais conexoes simultaneas ao PostgreSQL. Certifique-se de que o `POOL_SIZE` comporta a carga adicional. Uma regra pratica: `max_concurrency` de todos os workers nao deve exceder 50% do POOL_SIZE.
:::

### Escalar Workers com Mais Pods

Cada pod executa uma instancia de cada worker. Com 4 pods:

| Worker | Instancias | max_concurrency Total | Throughput Estimado |
|--------|-----------|----------------------|---------------------|
| InboundProcessor | 4 | 40 | ~8.000 TPS |
| OutboundSender | 4 | 40 | ~8.000 TPS |
| StatusUpdater | 4 | 40 | ~8.000 TPS |
| ReturnProcessor | 4 | 20 | ~4.000 TPS |
| CoreEventProcessor | 4 | 20 | ~4.000 TPS |

::: tip Consumers competidores
NATS JetStream distribui mensagens automaticamente entre consumers com o mesmo nome (durable consumer). Nao e necessario configuracao adicional — basta escalar os pods.
:::

## Load Testing com K6

### Teste Basico (200 TPS)

```bash
# Executar teste de carga basico
k6 run k6/simulator-e2e.js

# Saida esperada:
#      scenarios: (100.00%) 1 scenario, 200 max VUs, 5m30s max duration
#      iterations: 60000 total
#
#      http_req_duration ......: avg=45ms    min=12ms    med=38ms    max=890ms   p(90)=72ms    p(95)=95ms
#      http_req_failed ........: 0.12%
#      http_reqs ..............: 60000    200/s
#      iteration_duration .....: avg=250ms
```

### Teste de Carga Sustentada (5.000 TPS)

```bash
# Executar teste de 5K TPS
k6 run k6/load-5k-tps.js

# Configuracao do teste:
# - Ramp-up: 0 → 5000 VUs em 2 min
# - Sustentado: 5000 VUs por 10 min
# - Ramp-down: 5000 → 0 VUs em 1 min
```

### Teste de Validacao Pos-Deploy

```bash
# Teste rapido de validacao (RBAC + idempotency + 1K TPS)
k6 run k6/phase12-validation.js

# Saida esperada:
#      checks .................: 98.5% (passes: 29550, fails: 450)
#      http_reqs ..............: 30000   1000/s
```

## Planejamento de Capacidade

### Tabela de Recursos por TPS

| TPS Alvo | Backend Pods | POOL_SIZE | DB Conexoes | Redis | NATS Replicas | CPU Total | RAM Total |
|----------|-------------|-----------|-------------|-------|---------------|-----------|-----------|
| 100 | 2 | 50 | 400 | Standalone | 1 | 4 cores | 4 GiB |
| 500 | 2 | 100 | 800 | Standalone | 1 | 4 cores | 4 GiB |
| 1.000 | 3 | 150 | 1.800 | Standalone | 1 | 6 cores | 9 GiB |
| 2.500 | 4 | 200 | 3.200 | Cluster 3M | 3 | 12 cores | 16 GiB |
| 5.000 | 6 | 200 | 4.800 | Cluster 3M+3R | 3 | 24 cores | 24 GiB |
| 7.500 | 8 | 150 | 4.800 | Cluster 3M+3R | 3 | 32 cores | 48 GiB |

### Armazenamento Estimado

| Componente | Por Transacao | 1M TX/dia | 30M TX/mes |
|-----------|--------------|-----------|------------|
| monetarie_spi.messages | ~2 KB | 2 GB | 60 GB |
| monetarie_spi.payments | ~1 KB | 1 GB | 30 GB |
| monetarie_spi.message_history | ~0.5 KB | 0.5 GB | 15 GB |
| monetarie_audit.xml_audit_logs | ~5 KB | 5 GB | 150 GB |
| NATS JetStream (7 dias) | ~1 KB | 7 GB | N/A (rotacao) |
| Redis (volatile) | ~0.1 KB | 100 MB | N/A (TTL) |

## Identificacao de Gargalos

### Checklist de Diagnostico

| Sintoma | Possivel Gargalo | Diagnostico | Solucao |
|---------|-----------------|-------------|---------|
| Latencia alta em API | Conexoes DB esgotadas | `SHOW max_connections;` + pool checkout time | Aumentar POOL_SIZE ou pods |
| NATS consumer lag crescente | Workers lentos | Log de heartbeat (processed/s) | Aumentar max_concurrency |
| CPU saturada (>90%) | Processamento pesado | `kubectl top pods -n pix` | Mais pods ou mais CPU/pod |
| Memoria crescente | Memory leak ou cache | Metricas VM (vm.memory.total) | Investigar com `:observer` |
| Timeouts no circuit breaker | Servico downstream lento | CircuitBreaker state_change events | Verificar servico downstream |
| Error rate > 1% | Falhas de negocio ou infra | Logs de erro + metricas | Investigar causa raiz |
| Redis latencia alta | Muitas operacoes | `redis-cli LATENCY LATEST` | Redis Cluster ou tuning |

### Comandos de Diagnostico

```bash
# Verificar uso de CPU/Memoria dos pods
kubectl top pods -n pix
# Saida esperada:
# NAME                           CPU(cores)   MEMORY(bytes)
# pix-backend-7b8f9d6c4-abc12   850m         1.2Gi
# pix-backend-7b8f9d6c4-def34   920m         1.3Gi

# Verificar conexoes ativas no PostgreSQL
psql -h 10.140.241.2 -U postgres -d monetarie -c "
  SELECT count(*), state
  FROM pg_stat_activity
  WHERE datname = 'monetarie'
  GROUP BY state;
"
# Saida esperada:
#  count | state
# -------+--------
#    320 | active
#    180 | idle
#     50 | idle in transaction

# Verificar consumer lag no NATS
nats consumer info MONETARIE_SPI inbound-processor \
  --server=nats://10.10.40.5:4222 | grep -E "Pending|Redelivered"
# Saida esperada:
#   Pending Messages: 0
#   Redelivered Messages: 12

# Verificar throughput dos workers (logs)
kubectl logs deployment/pix-backend -n pix --tail=5 | grep Heartbeat
# Saida esperada:
# [InboundProcessor] Heartbeat: processed=4521 failed=3 retried=12 uptime=3600s
```

## Resultado Esperado

Ao seguir este guia, voce sera capaz de:

- Configurar HPA para escalabilidade automatica baseada em CPU/memoria
- Ajustar connection pooling do PostgreSQL para multiplos pods
- Configurar Redis Cluster para alta disponibilidade
- Tunar workers NATS para throughput desejado (batch_size, max_concurrency, poll_interval)
- Executar testes de carga com K6 para validar capacidade
- Identificar e resolver gargalos de desempenho com comandos de diagnostico
- Planejar recursos para crescimento futuro com base na tabela de capacidade
