Какие основные паттерны использования брокеров сообщений (Message Brokers)?

«Какие основные паттерны использования брокеров сообщений (Message Brokers)?» — вопрос из категории Брокеры сообщений, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Брокеры сообщений (Kafka, RabbitMQ, ActiveMQ) используются для реализации различных архитектурных паттернов. Выбор паттерна зависит от требований к доставке, порядку сообщений и масштабированию.

1. Асинхронная коммуникация / Развязка сервисов:

  • Цель: Отвязать отправителя (producer) от получателя (consumer) во времени и в пространстве.
  • Как: Producer публикует сообщение в очередь/топик и продолжает работу, не дожидаясь обработки.

2. Очередь задач (Task Queue / Worker Queue):

  • Цель: Распределить фоновые задачи между несколькими воркерами для балансировки нагрузки.
  • Реализация в RabbitMQ: Одна очередь, несколько потребителей. Каждое сообщение доставляется только одному потребителю (распределение по round-robin).
// Producer отправляет задачу
rabbitTemplate.convertAndSend("task_queue", "Task data");

// Consumer (Worker) обрабатывает задачу
@RabbitListener(queues = "task_queue")
public void handleTask(String task) {
    processTask(task);
}

3. Публикация/Подписка (Pub/Sub):

  • Цель: Одно сообщение доставить множеству независимых подписчиков.
  • Реализация:
    • RabbitMQ: Использование Fanout или Topic exchange. Exchange рассылает копии сообщения во все привязанные очереди.
    • Kafka: Consumer группы. Каждая группа получает все сообщения из топика.

4. Трансляция событий (Event Streaming):

  • Цель: Построение потоков событий, которые можно повторно читать, обрабатывать и хранить.
  • Реализация: Используется Apache Kafka — сообщения сохраняются в топиках с retention policy. Множество потребителей могут читать топик независимо, со своей позицией (offset).
// Kafka Producer
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;

public void sendEvent(String topic, String key, String event) {
    kafkaTemplate.send(topic, key, event);
}

// Kafka Consumer
@KafkaListener(topics = "order-events", groupId = "notification-service")
public void listen(ConsumerRecord<String, String> record) {
    log.info("Received event: key={}, value={}", record.key(), record.value());
}

5. Гарантированная доставка и отказоустойчивость:

  • Подтверждения (Acknowledgements): Consumer явно подтверждает обработку, и только тогда сообщение удаляется из очереди.
  • Сохраняемость (Persistence): Сообщения записываются на диск перед подтверждением producer'у.
  • Повторная доставка (Dead Letter Queue): Необработанные сообщения перемещаются в специальную очередь для анализа.

Сравнение Kafka и RabbitMQ для паттернов:

  • Очередь задач, RPC: Чаще выбирают RabbitMQ из-за гибких моделей очередей и встроенных механизмов подтверждения.
  • Поток событий, лог изменений, большие объемы данных: Выбирают Kafka из-за высокой пропускной способности, сохранения истории и возможности повторной обработки.