Ya leíste cómo encajan los subjects de NATS, los streams de JetStream, los mirrors de KV, las proyecciones CQRS y la observabilidad en las partes 1–5 de esta serie. También viste dónde se ubica un bus de mensajes en una arquitectura en crecimiento en Las piezas del diseño de software moderno y eficaz. La pregunta que queda es directa: ¿cuándo es NATS el bus adecuado y cuándo conviene recurrir a Kafka o AWS SQS?
Este artículo es un framework de decisión, no una competencia en la que solo puede haber un ganador. Las afirmaciones que siguen se basan en documentación oficial. Cuando una fila refleja criterio de ingeniería —por ejemplo, la carga operativa típica de un equipo pequeño— se indica que es una inferencia.
Investigación basada en docs.nats.io, la documentación de Apache Kafka y la documentación de AWS SQS el July 6, 2026.
TL;DR
- Core NATS ofrece pub/sub en memoria con entrega como máximo una vez, request/reply y queue groups: es excelente para mensajería interna en vivo cuando los suscriptores están conectados.
- JetStream (integrado en
nats-server) agrega streams durables, replay, KV y semántica de entrega al menos una vez o exactamente una vez mediante configuración explícita: la respuesta de NATS al desacoplamiento temporal sin adoptar una plataforma independiente. - Kafka es un log de eventos distribuido: los topics están particionados, se retienen y permiten replay por diseño; el procesamiento de streams (Kafka Streams, Connect y su ecosistema) es la principal razón por la que los equipos lo adoptan.
- SQS es una cola punto a punto administrada en AWS: no hay que operar un clúster, las colas estándar ofrecen entrega al menos una vez y las FIFO ofrecen procesamiento exactamente una vez cuando necesitas orden; no es un log ni ofrece pub/sub nativo.
- Elige según los síntomas (consumidores desconectados, ventana de replay, forma del fan-out, tolerancia a la dependencia de un proveedor cloud y quién opera el clúster), no según clasificaciones de latencia sin fuentes.
Qué aprenderás aquí
- En qué se diferencian NATS (Core + JetStream), Kafka y SQS en ocho dimensiones de ingeniería
- Cuándo gana NATS, incluidos los patrones de la parte 1 (request/reply, queue groups), la parte 2 (streams/consumidores), la parte 3 (KV) y la parte 4 (infraestructura interna de conexión)
- Cuándo gana Kafka: retención de logs, particiones y procesamiento de streams
- Cuándo gana SQS: desacoplamiento nativo de AWS sin operar brokers
- Un flujo de decisión en ASCII y tablas de síntoma → opción adecuada que puedes pegar en un ADR
Contexto de la serie: Parte 1 · Parte 2 · Parte 3 · Parte 4 · Parte 5
Tres primitivas diferentes
Antes de la tabla comparativa, aclaremos qué es cada sistema:
| Sistema | Abstracción principal | Modelo mental |
|---|---|---|
| Core NATS | Pub/sub basado en subjects | Enrutamiento sin esperar respuesta; los suscriptores deben estar conectados |
| JetStream | Stream durable + consumidor | Captura, replay y entrega basada en ack sobre el transporte de NATS |
| Kafka | Log de confirmación particionado | Topics de solo escritura al final; los consumidores registran offsets; la retención es un parámetro de primer nivel |
| SQS | Cola alojada | El productor encola; un grupo de consumidores procesa; el mensaje se elimina después del ack |
Core NATS JetStream Kafka SQS
───────── ───────── ───── ───
Pub ──► Sub Pub ──► Stream ──► Cons Pub ──► Topic (log) Pub ──► Queue ──► Worker
(live only) (persist + replay) ──► many consumers (point-to-point)
(offsets, retention)
SQS no es un sustituto directo de Kafka ni del pub/sub de NATS. AWS documenta SQS como un mecanismo de desacoplamiento mediante colas; para hacer fan-out a muchos suscriptores, normalmente se combina SNS → SQS (descripción general de SQS).
Dimensiones de comparación
Semántica de entrega
| Dimensión | Core NATS | JetStream | Kafka | SQS (estándar) | SQS (FIFO) |
|---|---|---|---|---|---|
| Garantía predeterminada | Como máximo una vez, mejor esfuerzo (¿Qué es NATS?) | Al menos una vez; la retención de tipo work-queue puede buscar el consumo exactamente una vez por mensaje (JetStream) | Al menos una vez por defecto; un productor idempotente + transacciones permiten entrega exactamente una vez dentro de Kafka cuando se configuran (diseño de Kafka — semántica) | Al menos una vez (tipos de cola de SQS) | Procesamiento exactamente una vez con deduplicación (tipos de cola de SQS) |
| Suscriptor desconectado | Se pierde el mensaje | Replay desde el stream | Lectura desde el log retenido | El mensaje espera en la cola (hasta el límite de retención) | Igual |
| Expectativa de idempotencia | Diseña siempre para ella | Diseña siempre para ella | Necesaria en rutas de entrega al menos una vez | Necesaria (puede haber duplicados en colas estándar) | Menor riesgo de duplicados; valida de todos modos |
Nota de ingeniería: «Exactamente una vez» suele significar «exactamente una vez bajo los modelos de falla documentados». La documentación de Kafka aclara que la entrega de extremo a extremo exactamente una vez hacia sistemas externos requiere la cooperación de esos sistemas.
Modelo de persistencia
| Dimensión | Core NATS | JetStream | Kafka | SQS |
|---|---|---|---|---|
| Almacenamiento | Solo en memoria; nunca se escribe en disco (¿Qué es NATS?) | Streams en archivo o memoria; límites de retención (max_age, max_bytes, política de descarte) | Segmentos de log en los discos de los brokers; retención por topic | Almacenamiento redundante entre AZs; retención predeterminada de 4 días, máximo de 14 días (descripción general de SQS) |
| Archivo a largo plazo | No | Limitado por los límites del stream | Sí: semanas/meses son habituales; según la documentación de diseño de Kafka, «almacenar datos durante mucho tiempo es perfectamente aceptable» | No: el consumo elimina los mensajes; no es un log analítico |
| Orden | Sin orden global | Orden por subject dentro de un stream | Orden total por partición | Colas FIFO: orden dentro de cada grupo de mensajes |
Complejidad operativa
| Dimensión | NATS (autoalojado) | Kafka (autoalojado) | SQS |
|---|---|---|---|
| Proceso que operar | Un solo binario nats-server; JetStream habilitado en la configuración | Clúster con varios brokers; ZooKeeper está obsoleto: modo KRaft en versiones modernas | Ninguno: API totalmente administrada |
| Modelo de escalado | Clúster + replicación RAFT de JetStream (1–5 réplicas por stream) | Particiones, brokers, ISR y rebalanceo | Automático; límites de tasa de la API por tipo de cola |
| Aspectos de operación continua | TLS, cuentas/JWT, ajuste de streams/consumidores, respaldo del almacenamiento de JetStream | Planificación de particiones, lag de consumidores, disco de brokers, operación de conectores y actualizaciones | IAM, redrive de DLQ, ajuste del visibility timeout y aumentos de cuota |
| Inferencia: carga para un equipo pequeño | Menor para Core NATS; moderada con JetStream HA | Mayor: asigna la responsabilidad a alguien con enfoque de plataforma | Menor superficie operativa si ya estás en AWS |
La documentación de NATS describe nats-server como de «menos de 20 MB» (¿Qué es NATS?). Eso habla de su tamaño de despliegue, no de su rendimiento.
Fan-out vs cola
| Patrón | Core NATS | JetStream | Kafka | SQS |
|---|---|---|---|---|
| Fan-out pub/sub | Nativo: cada suscriptor recibe una copia | Nativo: varios consumidores en un stream | Nativo: varios grupos de consumidores por topic | No nativo: usa fan-out de SNS hacia varias colas |
| Cola de trabajo / consumidores en competencia | Queue groups | Retención work-queue + consumidores de cola | Grupo de consumidores con asignación de particiones | Un consumidor recibe cada mensaje en curso (visibility timeout) |
| RPC request/reply | Patrón de inbox integrado (parte 1) | Posible, pero no es su caso ideal | Poco habitual: no es la API principal | No está soportado |
Replay
| Capacidad | Core NATS | JetStream | Kafka | SQS |
|---|---|---|---|---|
| Replay posterior | No | Sí: por secuencia, tiempo, último mensaje y velocidad de replay (JetStream) | Sí: el consumidor restablece el offset; los eventos no se eliminan al leerlos (introducción a Kafka) | No hay un replay significativo: los mensajes se consumen y se eliminan |
| Varias posiciones de lectura independientes | N/A | Varios consumidores por stream | Varios grupos de consumidores | N/A (semántica de cola) |
| Reprocesar lentamente el tráfico de producción | No | Política de replay original | Restablecer offsets / crear un grupo de consumidores | No aplica |
Perfil de latencia (solo cualitativo)
La documentación oficial describe mecanismos, no clasificaciones de latencia entre proveedores. Razona de forma cualitativa:
| Factor | NATS Core | JetStream | Kafka | SQS |
|---|---|---|---|---|
| Recorrido | Enrutamiento por subject, en memoria | Persistir → replicar → entregar | Escritura y lectura del log orientadas a lotes | API HTTPS + almacenamiento administrado |
| Caso ideal típico (inferencia) | Tráfico en vivo del plano de control, RPC | Eventos internos durables con retención moderada | Pipelines de alto volumen con procesamiento por lotes | Transferencia asíncrona de trabajos entre servicios de AWS |
| Qué no hacer | Afirmar «X ms más rápido que Y» sin tus propios benchmarks en tu red | Igual | Igual | Igual |
En SQS, el polling frente al long polling y el visibility timeout afectan directamente la demora observada de extremo a extremo (ciclo de vida del mensaje): ajústalos antes de cambiar de broker.
Multi-cloud / portabilidad
| Dimensión | NATS | Kafka | SQS |
|---|---|---|---|
| Ejecución en cualquier entorno | Sí: binario en servidores físicos, VMs, K8s y edge (¿Qué es NATS?) | Sí: autoadministrado o administrado por un proveedor (MSK, Confluent, Aiven, etc.) | Solo AWS |
| Ofertas administradas | Synadia NGS, varias nubes | Muchas | Nativo de AWS |
| Acoplamiento al protocolo | Protocolo de comunicación de NATS | Protocolo de Kafka + amplio ecosistema | AWS SDK / API HTTP |
| Inferencia: costo de salida | Bajo si es autoalojado; mayor si depende de un solo proveedor de NATS administrado | Moderado: el ecosistema genera dependencia | Alto: integración más profunda y migración directa más difícil |
Modelo de costos (matiza cada afirmación)
| Factor de costo | NATS (autoalojado) | Kafka (autoalojado) | SQS |
|---|---|---|---|
| Facturación | Infraestructura que pagas (CPU, disco, red): el servidor OSS no tiene licencia por mensaje | Igual + a menudo mayor uso de disco para retención | Precio por solicitud; payload de 1 MiB = hasta 16 unidades de solicitud (precios de SQS) |
| Nivel gratuito | N/A (pagas tu infraestructura cloud) | N/A | 1 millón de solicitudes/mes (precios de SQS) |
| Costos ocultos | Réplicas HA, monitoreo, guardias | VMs para conectores, schema registry, clústeres más grandes | KMS, transferencia entre regiones, cliente extendido de S3 para payloads grandes |
| Inferencia | Rentable con un volumen interno estable en K8s existente | Rentable cuando la retención del log reemplaza otros pipelines de almacenamiento | Rentable para código de integración de AWS con picos de tráfico si el número de solicitudes se mantiene acotado |
No extrapoles cuál es la opción «más barata» solo a partir de los precios de lista: modela las solicitudes, el tamaño del payload, los GB-mes de retención y el tiempo de ingeniería.
Cuándo gana NATS
NATS encaja cuando la mensajería es infraestructura interna —de servicio a servicio, de edge a cloud, plano de control— y quieres un runtime liviano que abarque tanto el pub/sub de Core como la durabilidad de JetStream.
| Síntoma | Cómo encaja NATS | Referencia de la serie / documentación |
|---|---|---|
| Los servicios necesitan RPC sin usar HTTP en todas partes | Request/reply de Core | Parte 1 |
| Los workers deben compartir la carga de un subject | Queue groups o streams work-queue de JetStream | Parte 1, parte 2 |
| Los suscriptores se desconectan brevemente; los eventos deben sobrevivir | Streams de JetStream + consumidores durables | Parte 2 |
| Último estado de una entidad + notificaciones de cambios | watch de JetStream KV | Parte 3 |
| Postgres es la fuente de verdad; el bus conecta con el buscador/warehouse | CDC → KV → subjects de indexación | Parte 4 |
| Mismo contexto de seguridad desde edge hasta cloud | Cuentas/JWT de NATS 2.0; un solo binario | ¿Qué es NATS? |
| Quieres persistencia sin un equipo independiente de «plataforma de streaming» | JetStream integrado en nats-server | JetStream |
Internal mesh style (NATS sweet spot)
API ──request/reply──► Authz svc
│
└──publish──► orders.created ──► [billing worker]
└──► [analytics projector]
JetStream stream (optional durability)
└──► KV mirror ──watch──► indexer
Cuándo NATS es una opción predeterminada menos conveniente (inferencia):
- Analítica de varios equipos sobre meses de historial inmutable con herramientas SQL sobre streams
- El estándar de la organización ya es Kafka Connect + Flink + schema registry
- El equipo no tiene ninguna disposición para operar un broker de mensajes: SQS/Lambda puede ganar solo por razones operativas
Cuándo gana Kafka
Kafka encaja cuando el log en sí es el producto: ingesta de alto volumen, muchos consumidores posteriores a distintas velocidades, retención prolongada y procesamiento de streams.
| Síntoma | Cómo encaja Kafka | Referencia de la documentación |
|---|---|---|
| Muchos equipos leen el mismo topic desde distintos offsets | Grupos de consumidores + log retenido | Introducción a Kafka — topics |
| Event sourcing / auditoría con replay meses después | Retención configurable; diseño orientado a disco | Diseño de Kafka — persistencia |
| Joins, ventanas y agregaciones de streams en la capa del bus | API de Kafka Streams | APIs de Kafka |
| Ingesta desde Postgres, S3, Elasticsearch mediante conectores administrados | Kafka Connect | APIs de Kafka — Connect |
| Localidad por clave de partición (orden por usuario) | Mapeo de clave → partición | Diseño de Kafka — productor |
| Entrega exactamente una vez entre topics de Kafka en un pipeline | Productor transaccional + read_committed | Semántica de Kafka |
Log-centric analytics (Kafka sweet spot)
Producers ──► topic (partitions P0..Pn, replicated)
│
┌───────────┼───────────┬──────────────┐
▼ ▼ ▼ ▼
Warehouse Flink job Search sink Audit archive
(Connect) (Streams) (Connect) (long retention)
Compromisos que debes aceptar: cantidad de brokers, planificación de particiones, dashboards de lag de consumidores y disciplina para las actualizaciones. La documentación de diseño de Kafka apunta a «streams de eventos de alto volumen» y «cargas periódicas de datos desde sistemas desconectados», no a RPC interno minimalista.
Cuándo gana SQS
SQS encaja cuando las cargas de trabajo son nativas de AWS, tienen forma de cola y quieres que AWS se encargue de la disponibilidad.
| Síntoma | Cómo encaja SQS | Referencia de la documentación |
|---|---|---|
| Desacoplar workers de Lambda, ECS y EC2 | Cola estándar + mapeo de origen de eventos | Descripción general de SQS |
| No hay equipo para operar Kafka/NATS | Totalmente administrado | Descripción general de SQS |
| Es necesario inspeccionar mensajes fallidos | Dead-letter queues + redrive | DLQ de SQS |
| Orden estricto por entidad | FIFO + ID de grupo de mensajes | Tipos de cola de SQS |
| Fan-out a muchos workers en AWS | SNS → varias colas SQS | SQS vs SNS |
| Retención medida en días, no en meses | Retención predeterminada de 4d, máximo de 14d | Descripción general de SQS |
AWS glue (SQS sweet spot)
API Gateway / ALB ──► SQS ──► Lambda / ECS worker
│
└── on failure ──► DLQ ──► redrive / alarm
Cuándo SQS es una opción predeterminada menos conveniente (inferencia):
- Pub/sub nativo con decenas de suscriptores activos en el mismo subject
- Replay desde offsets históricos arbitrarios para nuevos consumidores
- Despliegue principal multi-cloud o local
- Request/reply entre microservicios internos (usa HTTP/gRPC o NATS Core en su lugar)
Flujo de decisión
Start: async communication needed
│
▼
┌─────────────────────────────────────┐
│ Must run outside AWS or multi-cloud? │
└─────────────────────────────────────┘
│ yes │ no
▼ ▼
┌───────────────────┐ ┌──────────────────────┐
│ Need log retention │ │ Queue + AWS services │
│ + stream ecosystem│ │ only? │
└───────────────────┘ └──────────────────────┘
│ yes │ no │ yes │ no
▼ ▼ ▼ ▼
┌────────┐ ┌─────────────────────────┐ ┌────────┐
│ Kafka │ │ Subscribers often offline │ │ SQS │
│ │ │ or need replay/KV/RPC? │ │ (+SNS │
└────────┘ └─────────────────────────┘ │ if fan-│
│ yes │ no │ out) │
▼ ▼ └────────┘
┌─────────┐ ┌──────────┐
│JetStream│ │Core NATS │
│(+ Core │ │(live fan-│
│ as RPC) │ │out, RPC) │
└─────────┘ └──────────┘
Implementación concreta: guía de selección basada en síntomas
Usa esta sección como apéndice de un ADR. Cada fila relaciona un síntoma en producción con una opción predeterminada razonable y el primer parámetro de configuración que debes verificar.
Síntoma → opción adecuada (patrón de mensajería)
| Síntoma | Opción predeterminada razonable | Primer parámetro que revisar |
|---|---|---|
| «Facturación debe cobrar exactamente una vez por ID de pedido» | Stream work-queue de JetStream o SQS FIFO con deduplicación o productor idempotente de Kafka + consumidor idempotente | Clave de idempotencia en tu handler en cualquiera de los casos |
| «El indexador de búsqueda puede retrasarse 30s; la API lee de Postgres» | JetStream o Kafka para el flujo de cambios; no Core NATS por sí solo | Tiempo de espera del ack / máximo de entregas del consumidor (parte 2) |
| «10 microservicios necesitan el mismo evento en vivo sin esperar respuesta» | Pub/sub de Core NATS | Suscriptores simples vs de cola (parte 1) |
| «Un equipo nuevo quiere ejecutar SQL sobre 90 días de clics» | Kafka (+ sink hacia un warehouse) | Bytes / tiempo de retención del topic |
| «Lambda procesa cargas de archivos durante la noche» | SQS estándar | Visibility timeout ≥ duración p99 del handler |
| «El servicio A llama al servicio B de forma síncrona internamente» | Request/reply de Core NATS | Timeout + manejo de ErrNoResponders |
| «Compartir la configuración más reciente por región» | JetStream KV + watch | Número de réplicas del bucket (parte 3) |
| «Entrega exactamente una vez del topic A al topic B» | Transacciones de Kafka | isolation.level=read_committed |
| «Fan-out a 50 colas SQS en AWS» | SNS → SQS | Política de cola por suscriptor |
Síntoma → opción adecuada (restricciones operativas)
| Síntoma | Inclínate por | Por qué (con respaldo en fuentes o inferencia) |
|---|---|---|
| «No tenemos un SRE para mensajería» | SQS en AWS | Servicio administrado (descripción general de SQS): inferencia sobre el tamaño del equipo |
| «Ya operamos K8s y queremos un solo binario pequeño» | NATS | Un solo proceso de servidor (¿Qué es NATS?) |
| «Cumplimiento exige un log de auditoría inmutable durante 1 año» | Kafka | Modelo de retención (introducción a Kafka) |
| «Picos de millones/segundo y la facturación de AWS es aceptable» | SQS estándar | Escala sin aprovisionamiento (descripción general de SQS) |
| «Dispositivos edge + cloud en el mismo bus» | NATS | Modelo de despliegue (¿Qué es NATS?): inferencia para edge |
Ejemplos mínimos de integración (prueba básica de la elección)
NATS JetStream — evento durable de pedido (del contexto de la serie):
nats stream add ORDERS \
--subjects "orders.>" \
--storage file \
--retention limits \
--max-age 7d \
--replicas 3
Kafka — topic con retención explícita (ilustrativo):
# server.properties / topic config
log.retention.hours=168
min.insync.replicas=2
SQS — visibility timeout ajustado al handler (AWS CLI):
aws sqs set-queue-attributes \
--queue-url "$QUEUE_URL" \
--attributes VisibilityTimeout=300
Si no puedes explicar qué fila de las tablas anteriores corresponde a tu síntoma, aún no estás listo para elegir un broker: define primero la garantía de entrega y la ventana de retención.
Arquitecturas híbridas (comunes en la práctica)
Los sistemas reales combinan herramientas:
| Patrón | Composición |
|---|---|
| Entrada en AWS, bus interno | ALB → SQS → servicio puente → NATS JetStream |
| Analítica a partir de eventos internos | NATS JetStream → (conector) → Kafka → warehouse |
| Migración de sistemas heredados a cloud | NATS local ↔ superclúster ↔ NATS en cloud; SQS solo en el límite de AWS |
Las soluciones híbridas agregan puntos de integración operativos: documenta quién se encarga de los reintentos, la DLQ y el esquema en cada límite.
Errores comunes
- Elegir Kafka para RPC interno. Request/reply no es el caso ideal de Kafka; usa HTTP/gRPC o NATS Core.
- Elegir SQS para pub/sub. Usa fan-out de SNS o un bus con subjects/topics nativos.
- Usar Core NATS para eventos de facturación. Entrega como máximo una vez + suscriptores desconectados = pérdida silenciosa (¿Qué es NATS?).
- Esperar replay de SQS. Una vez eliminado un mensaje, desaparece: no es un log.
- Ignorar la idempotencia. La entrega al menos una vez es la opción predeterminada en casi todas partes.
- Elegir según benchmarks. El marketing de los proveedores y los artículos de blog desactualizados no representan la topología de tu red.
Cómo encaja esto en la serie
| Parte | Enfoque |
|---|---|
| 1 | Primitivas de Core NATS |
| 2 | Durabilidad de JetStream |
| 3 | KV como stream de cambios |
| 4 | Proyecciones CQRS con NATS como infraestructura de conexión |
| 5 | Observabilidad y SLOs |
| 6 (este artículo) | Cuándo usar NATS vs Kafka vs SQS |
Para conocer los niveles de la arquitectura (outbox, proyecciones, búsqueda), consulta Las piezas del diseño de software moderno y eficaz.
Fuentes
- ¿Qué es NATS? — QoS, Core vs JetStream, escala de despliegue
- Core NATS — pub/sub con entrega como máximo una vez
- JetStream — streams, retención, replay, replicación, KV
- Almacén clave/valor de JetStream — buckets de KV y semántica de watch
- Apache Kafka — Introducción — topics, particiones, grupos de consumidores, APIs
- Apache Kafka — Diseño — persistencia del log, particionamiento del productor, consumo por pull
- Apache Kafka — Semántica de entrega de mensajes — entrega al menos una vez, exactamente una vez, transacciones
- Amazon SQS — ¿Qué es Amazon SQS? — ciclo de vida de la cola, comparación con SNS
- Amazon SQS — Tipos de cola — garantías de las colas estándar vs FIFO
- Amazon SQS — Dead-letter queues — redrive y
maxReceiveCount - Precios de Amazon SQS — facturación por solicitud y división de payloads en fragmentos