Для чего нужен Acknowledge (ACK) в RabbitMQ?

«Для чего нужен Acknowledge (ACK) в RabbitMQ?» — вопрос из категории Брокеры сообщений, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Подтверждение (Acknowledge, ACK) — это механизм, с помощью которого потребитель (consumer) явно сообщает брокеру RabbitMQ, что сообщение было успешно получено и обработано. Это основа гарантированной доставки (at-least-once delivery).

Проблема, которую решает ACK: Без подтверждения (autoAck: true) сообщение немедленно удаляется из очереди после отправки потребителю. Если процесс потребителя упадёт во время обработки, сообщение будет потеряно навсегда.

Как работает ручное подтверждение (autoAck: false):

  1. RabbitMQ отправляет сообщение потребителю и помечает его как "неподтверждённое" (unacknowledged).
  2. Сообщение остаётся в очереди (логически, хотя и не доступно для других потребителей), пока не получит ACK.
  3. После успешной обработки потребитель отправляет BasicAck с deliveryTag (уникальный идентификатор доставки).
  4. RabbitMQ удаляет сообщение из очереди.

Пример кода на .NET (RabbitMQ.Client):

var channel = connection.CreateModel();
channel.QueueDeclare("task_queue", durable: true, exclusive: false, autoDelete: false, arguments: null);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false); // Честное распределение

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, ea) =>
{
    var body = ea.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine($" [x] Получено: {message}");

    try
    {
        // Имитация обработки задачи
        ProcessMessage(message);
        // ЯВНОЕ ПОДТВЕРЖДЕНИЕ УСПЕШНОЙ ОБРАБОТКИ
        channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
        Console.WriteLine($" [v] Обработано и подтверждено: {message}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($" [!] Ошибка обработки: {ex.Message}");
        // Отрицательное подтверждение (NACK) с requeue = true
        channel.BasicNack(deliveryTag: ea.DeliveryTag, multiple: false, requeue: true);
        // Сообщение вернётся в очередь для повторной попытки обработки.
    }
};

// Запуск потребителя с ВЫКЛЮЧЁННЫМ autoAck
channel.BasicConsume(queue: "task_queue", autoAck: false, consumer: consumer);

Типы подтверждений:

  • BasicAck: Положительное подтверждение. Сообщение можно удалять.
  • BasicNack (Negative Acknowledgement): Отрицательное подтверждение. Сообщение можно либо отбросить, либо вернуть в очередь (requeue: true).
  • BasicReject: Устаревший аналог BasicNack с одним флагом requeue.

Итог: Использование ручного ACK критически важно для построения отказоустойчивых систем, где потеря сообщений недопустима.