NATS JetStream: mensageria persistente e rápida para sistemas distribuídos

1. Introdução ao NATS e ao JetStream

NATS é um sistema de mensageria open source conhecido por sua simplicidade, alto desempenho e latência extremamente baixa. Originalmente criado pela Cloud Foundry e posteriormente mantido pela CNCF, o NATS Core oferece comunicação publish/subscribe e request/reply com entrega "at-most-once". Essa simplicidade, porém, limitava seu uso em cenários que exigiam persistência, garantias de entrega mais fortes e replay de mensagens.

O JetStream surge como uma extensão nativa do NATS para superar essas limitações. Construído sobre o mesmo protocolo leve, o JetStream adiciona:

  • Persistência baseada em arquivo com replicação via Raft
  • Garantias de entrega at-least-once e exactly-once
  • Replay de mensagens e filas duráveis
  • Armazenamento de objetos e chave-valor

Diferente de soluções como Kafka, o JetStream mantém a simplicidade operacional do NATS, sendo executado como um único binário e configurado via API REST ou CLI.

2. Conceitos Fundamentais do JetStream

Streams

Streams são sequências ordenadas e persistentes de mensagens. Cada stream pertence a um ou mais subjects (tópicos) e armazena mensagens conforme políticas de retenção configuradas.

# Criando um stream via CLI
nats stream add ORDERS --subjects "orders.>" --storage file --retention limits --max-msgs 1000000 --max-age 365d

Consumers

Consumers são assinantes de streams com estado próprio. Existem dois modos:

  • Push consumer: o servidor envia mensagens para um endpoint (útil para microsserviços)
  • Pull consumer: o cliente solicita mensagens sob demanda (útil para filas de trabalho)
# Criando um consumer pull
nats consumer add ORDERS WORKER --pull --ack explicit --deliver all --max-deliver 5

Stores Adicionais

Além de streams, o JetStream oferece:

  • Object Store: armazenamento de arquivos grandes (até GBs)
  • Key-Value Store: armazenamento consistente com operações atômicas
# Criando uma KV store
nats kv add CONFIG --history 5
nats kv put CONFIG db_host localhost

3. Arquitetura e Modelo de Persistência

O JetStream utiliza um modelo de armazenamento baseado em arquivos com suporte a replicação síncrona via Raft. As principais estratégias de retenção são:

  • Limits: baseado em idade, tamanho ou quantidade máxima de mensagens
  • Interest: mantém mensagens até que todos os consumidores as reconheçam
  • Work Queue: mensagens são removidas após o primeiro reconhecimento

A desduplicação é feita através de um ID único (Nats-Msg-Id) e uma janela configurável (dedup window), garantindo que mensagens duplicadas não sejam armazenadas.

# Configurando desduplicação
nats stream add ORDERS --subjects "orders.>" --dedup 2m

4. Garantias de Entrega e Confiabilidade

O JetStream oferece três níveis de garantia:

  • At-least-once: com acknowledgments explícitos, mensagens são reentregues se não confirmadas
  • Exactly-once: combinando IDs de mensagem com dedup window e idempotência do consumidor
  • At-most-once: modo fire-and-forget (padrão NATS Core)

Para mensagens que excedem o limite de entregas, o JetStream suporta Dead Letter Queue (DLQ):

# Consumer com DLQ
nats consumer add ORDERS WORKER --max-deliver 3 --backoff 5s,10s,30s --dlq DLC_ORDERS

5. Performance e Escalabilidade

O JetStream foi projetado para alto throughput horizontal. Streams podem ser particionados (sharded) e consumidores paralelos processam partições independentes.

Principais características de performance:

  • Latência média: 1-5ms (vs 10-50ms do Kafka)
  • Throughput: até 1 milhão de mensagens/segundo por nó
  • Compressão: suporte nativo a compressão LZ4 e Snappy
  • Cache de índices: índices em memória para acesso rápido a mensagens
# Stream particionado (sharded)
nats stream add ORDERS --subjects "orders.>" --max-streams 4

Comparado ao Kafka, o JetStream oferece latência 5-10x menor e operação mais simples (sem Zookeeper). Comparado ao RabbitMQ, oferece throughput 3-5x maior e melhor escalabilidade horizontal.

6. Casos de Uso e Padrões de Integração

Event Sourcing e CQRS

Streams persistentes permitem armazenar eventos de domínio e reconstruir estado de agregados via replay.

# Replay de eventos
nats stream replay ORDERS --since "2024-01-01" --until "2024-06-30"

Filas de Trabalho (Work Queues)

Pull consumers com acknowledgments garantem processamento confiável de tarefas assíncronas.

# Consumidor pull em Python
import asyncio
from nats import connect

async def worker():
    nc = await connect()
    js = nc.jetstream()
    consumer = await js.pull_subscribe("orders.>", "WORKER")
    while True:
        msgs = await consumer.fetch(10, timeout=5)
        for msg in msgs:
            print(f"Processando: {msg.data}")
            await msg.ack()

Bridge com Outros Sistemas

O NATS suporta bridges nativas para Kafka, MQTT e WebSocket, permitindo integração com ecossistemas existentes.

# Configurando bridge NATS-Kafka
nats bridge add KAFKA_BRIDGE --type kafka --brokers localhost:9092 --topic orders

7. Operação, Monitoramento e Boas Práticas

Gerenciamento via CLI e API

# Listar streams
nats stream list

# Verificar lag de consumidor
nats consumer info ORDERS WORKER

# Monitorar em tempo real
nats stream stats ORDERS --wait

Métricas Chave

  • Lag: diferença entre última mensagem publicada e último offset consumido
  • Throughput: mensagens por segundo (publicação e consumo)
  • Utilização de disco: espaço ocupado por streams e índices
  • Replicação: estado Raft (líder, seguidor) e latência de replicação

Boas Práticas

  • Configurar políticas de retenção adequadas para evitar crescimento infinito
  • Usar dedup window para garantir idempotência em produtores
  • Monitorar lag com alertas para detectar consumidores lentos
  • Fazer backup regular dos diretórios de dados JetStream
  • Testar failover em clusters com replicação R3 (3 nós)
# Backup de stream
nats stream backup ORDERS --directory /backup/orders_2024

O JetStream representa a evolução do NATS para sistemas distribuídos que exigem persistência e confiabilidade sem abrir mão da simplicidade e performance. Seja para event sourcing, filas de trabalho ou integração entre microsserviços, o JetStream oferece uma solução madura e eficiente.


Referências