Альтернативы Kafka и RabbitMQ: NATS JetStream, Redpanda, Pulsar и облачные очереди

↑ 5.4 Очереди и брокеры: Kafka, RabbitMQ · ← Предыдущая

Желательно~9 мин чтенияУровень: senior

Зачем это на собесе

«Почему Kafka, а не NATS?» и «Чем Redpanda отличается от Kafka?» Интервьюер проверяет, выбираете ли вы брокер под задачу: модель доставки, хранение и повторное чтение, порядок, масштаб и цена эксплуатации. Kafka и RabbitMQ не единственные разумные варианты.

Подтемы

  • Что сравниваем: очередь, лог событий, pub/sub
  • NATS и JetStream
  • Redpanda
  • Apache Pulsar
  • Облачные сервисы: SQS/SNS, Service Bus, Pub/Sub
  • Как выбрать

Объяснение

Два класса систем

  • Очередь сообщений (RabbitMQ, SQS): сообщение доставляется потребителю и после подтверждения удаляется. Подходит для задач и команд («отправить письмо»).
  • Лог событий (Kafka, Redpanda, Pulsar, JetStream): события дописываются в упорядоченный журнал и хранятся заданное время. Несколько потребителей читают независимо и могут перечитать историю. Подходит для событий, потоков данных и восстановления состояния.

Подробнее о различиях: Kafka или RabbitMQ и гарантии доставки.

NATS и JetStream

NATS — лёгкий брокер на Go в одном бинарнике. В режиме Core это быстрый pub/sub и request-reply без хранения: сообщение получает только тот, кто подписан в момент публикации (at-most-once). JetStream добавляет хранение: именованные streams записывают сообщения по темам (subjects), а consumers читают их с подтверждениями (at-least-once), есть повторная доставка, дедупликация по Nats-Msg-Id, хранилища ключ-значение и объектов.

flowchart LR
    P["Издатель"] -->|"orders.created"| S["Stream ORDERS<br/>(subjects: orders.*)"]
    S --> C1["Consumer billing<br/>(durable)"]
    S --> C2["Consumer shipping<br/>(durable)"]
    C1 --> A["Ack"]
    C2 --> A

Сильные стороны: простота эксплуатации, очень низкие задержки, лёгкие соединения, иерархия тем с подстановками (orders.*, orders.>), request-reply из коробки, работа на границе (edge) и в нескольких кластерах. Слабее Kafka в экосистеме коннекторов и потоковой обработки.

Redpanda

Совместим с API Kafka: существующие клиенты и инструменты работают без изменений. Написан на C++ в виде одного бинарника, без JVM и отдельного ZooKeeper, использует собственный Raft. Обещает меньшие задержки и проще эксплуатацию. Лицензия Community Edition относится к source-available (BSL), проверяйте условия.

Apache Pulsar

Отделяет вычисления от хранения: брокеры без состояния и слой хранения BookKeeper. Поддерживает мультитенантность, гео-репликацию, tiered storage, и как очередь (shared-подписки), и как лог (failover/exclusive). Функциональный, но сложный в эксплуатации.

Облачные сервисы

СервисМодельЗаметки
AWS SQSочередьпростая, без серверов, стандартная и FIFO очереди
AWS SNSpub/subрассылка в очереди и HTTP, часто SNS плюс SQS
AWS Kinesis, Azure Event Hubsлог событийуправляемые потоки, Event Hubs поддерживает протокол Kafka
Azure Service Busочередь и топикитранзакции, сессии, dead-letter
Google Pub/Subpub/subглобальный управляемый сервис
Confluent Cloud, MSKуправляемый Kafkaтот же протокол, оплата за сервис

Сравнение

KafkaRabbitMQNATS JetStreamRedpandaPulsar
Модельлогочередьpub/sub и логлог (API Kafka)лог и очередь
Хранение и перечитываниеданет (стримы отдельно)да (JetStream)дада
Порядоквнутри партициив очередивнутри stream / consumerвнутри партициивнутри ключа / партиции
Эксплуатациясредняя (KRaft без ZooKeeper с Kafka 4.0)прощеочень простопростосложно
Экосистемасамая большаябогатая маршрутизациярастётсовместима с Kafkaсвоя

Как выбрать

flowchart TD
    A["Нужен брокер"] --> B{"Нужны история и повторное чтение событий?"}
    B -- нет --> C{"Сложная маршрутизация и очереди задач?"}
    C -- да --> D["RabbitMQ или облачная очередь (SQS, Service Bus)"]
    C -- "простой pub/sub, минимум ресурсов" --> E["NATS Core"]
    B -- да --> F{"Экосистема Kafka (Connect, Streams, Schema Registry)?"}
    F -- да --> G["Kafka / Redpanda / Confluent"]
    F -- "нужна простота и малые задержки" --> H["NATS JetStream"]
    F -- "мультитенантность, гео-репликация" --> I["Pulsar"]

Примеры

NATS JetStream в .NET

using NATS.Client.Core;
using NATS.Client.JetStream;
using NATS.Client.JetStream.Models;
 
await using var nats = new NatsConnection(new NatsOpts { Url = "nats://localhost:4222" });
var js = new NatsJSContext(nats);
 
// Stream хранит сообщения по темам orders.*
await js.CreateStreamAsync(new StreamConfig("ORDERS", ["orders.*"]));
 
// публикация с подтверждением записи в stream
var ack = await js.PublishAsync("orders.created", new OrderCreated(42, 199.9m));
ack.EnsureSuccess();
 
// durable-потребитель: позиция хранится на сервере
var consumer = await js.CreateOrUpdateConsumerAsync("ORDERS",
    new ConsumerConfig("billing") { AckPolicy = ConsumerConfigAckPolicy.Explicit });
 
await foreach (var msg in consumer.ConsumeAsync<OrderCreated>())
{
    Console.WriteLine($"order {msg.Data?.Id}");
    await msg.AckAsync();           // без подтверждения сообщение будет доставлено повторно
}
 
public record OrderCreated(int Id, decimal Total);

Пакет NATS.Net. Потребитель должен быть идемпотентным: при повторной доставке обработка повторяется (идемпотентные консьюмеры).

Запуск NATS с JetStream

docker run -d --name nats -p 4222:4222 -p 8222:8222 nats:latest -js -m 8222

Флаг -js включает JetStream, -m 8222 мониторинг по HTTP.

Запуск Redpanda для разработки

docker run -d --name redpanda -p 9092:9092 \
  docker.redpanda.com/redpandadata/redpanda:latest \
  redpanda start --overprovisioned --smp 1 --memory 1G --reserve-memory 0M --node-id 0 --check=false

Клиенты подключаются как к Kafka: bootstrap.servers=localhost:9092. Параметры запуска зависят от версии образа, смотрите документацию.

Нюансы и подводные камни

  • Гарантии доставки различаются. NATS Core не хранит сообщения; для надёжности нужен JetStream с подтверждениями.
  • Порядок сообщений. Он гарантируется не глобально, а в пределах партиции, ключа или stream: проектируйте ключи.
  • Идемпотентность обязательна при любой доставке «минимум один раз».
  • Kafka API не значит Kafka целиком. Redpanda и другие совместимые системы могут иначе вести себя в редких сценариях (транзакции, Connect): проверяйте нужные функции.
  • Облачные очереди и лимиты. Размер сообщения, время видимости, порядок (FIFO), стоимость запросов: читайте ограничения сервиса.
  • Не усложняйте. Если хватает Postgres-очереди или RabbitMQ, второй брокер в инфраструктуре лишняя нагрузка на команду.
  • Схемы сообщений. Версионируйте и проверяйте совместимость независимо от брокера (Schema Registry).

Вопросы с ответами

Связанные темы