Мы рассмотрим парадокс и гарантии доставки, предлагаемые Kafka Producer, чтобы справиться с ним.

Прежде чем мы углубимся в детали продюсера Кафки и проблемы двух генералов. Давайте освежим основы —

Kafka — это распределенная система обмена сообщениями, в которой один или несколько производителей добавляют сообщения брокеру и одна или несколько групп потребителей читают сообщения от брокера.

данные хранятся в брокере. Существует ведущий брокер, и для надежности Kafka также реплицирует данные другим брокерам, известным как последующие брокеры. В случае неудачи ведущего брокера новым лидером избирается один из ведомых.

Доставку сообщения от производителя к потребителю можно разбить на два отдельных процесса:

  1. От производителя брокеру. Гарантии доставки предоставляются путем подтверждения от брокера.
  2. Брокер для потребителя. На основе опроса потребитель контролирует, сколько раз он может прочитать и обработать сообщение.

По той же причине Я также разделил гарантии доставки на 2 статьи — схемы доставки производителями и обработку сообщений потребителями.

В чем проблема двух генералов?

В задаче о двух генералах рассматривается пример двух армейских частей, которые планируют атаковать укрепленный город с двух разных направлений. Чтобы добиться успеха, два генерала должны быть в состоянии начать скоординированную атаку с обоих направлений.

Проблема в том, что посланники, несущие послание, должны пройти через долину, охраняемую городскими войсками. Поскольку сообщение отправляется через враждебную территорию, существует вероятность того, что защитники перехватят/захватят/убьют посланника. Нет нет гарантии, что последнее сообщение дошло до генерала на другой стороне. Без этой гарантии оба генерала оказываются перед дилеммой: генерал А не знает, дошло ли сообщение о нападении до генерала Б. А генерал Б не знает, дошло ли подтверждение до генерала А. Таким образом, оба будут колебаться в атаке. не зная, прибудет ли другое армейское подразделение для согласованного плана атаки.

Решение выглядит просто —

  1. Генерал-лидер, генерал А, инициирует сообщение о нападении: «Мы атакуем в 4 часа утра».
  2. Генерал Б должен подтвердить это: «Получил сообщение, атакуем в 4 часа утра».

Обычно этого достаточно для формирования консенсуса, но генерал Б не знает, получил ли генерал А это сообщение. Таким образом, для того, чтобы «Прикрепить подтверждение», необходимо еще одно подтверждение от генерала А. И это запускает бесконечный цикл подтверждений. Так что проблема неразрешима.

Есть несколько прагматичных способов решения этой проблемы:

  1. Интенсивная стоимость — если есть достаточно посланников, которым можно рискнуть, Генералы могут отправить несколько посланников одновременно, надеясь, что некоторые доберутся до другой стороны. Допустим, 100 мессенджеров, каждый из которых имеет свой порядковый номер. Даже если генерал на другой стороне получит одно сообщение, он знает, когда атаковать, а недостающие порядковые номера также сообщают генералу, насколько безопасна долина.
  2. Требует много времени. Если мессенджеров недостаточно, чтобы рисковать, может быть другой подход, при котором отсутствие сообщений укрепляет доверие. Допустим, время пересечения долины составляет 1 час, Генерал А продолжает отправлять сообщения Генералу Б каждые 1 час, пока не получит единственное подтверждение от Генерала Б. Если Генерал Б действительно получает сообщение в течение нескольких часов после отправки подтверждения, это означает, что генерал А получил подтверждение.

Гарантии доставки от Производителя Брокеру

Когда производитель отправляет сообщение Кафке, у него есть некоторые возможности выбора в соответствии с контекстом.

1. Никаких гарантий/выстрелил и забыл:

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

Настройка производителя: acks = 0

Гарантия долговечности отсутствует. Но это самый быстрый.

С точки зрения производителя это можно рассматривать как доставку не более одного раза, поскольку сообщения могут быть потеряны, но не дублируются.

2. Только Лидер-брокер сохраняет сообщение и подтверждает его.

Брокер подтверждает, что ведущий брокер записал сообщение в свое постоянное хранилище. Данные будут своевременно реплицированы на брокеры-последователи.

Настройка производителя: acks = 1

Долговечность намного выше, но существует небольшая вероятность того, что сообщение может потеряться, если во время создания сообщения происходят выборы лидера.

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

3. Самая сильная гарантия. Все (синхронные) брокеры сохраняют сообщение и подтверждают его.

Брокер подтверждает, когда все реплики брокера (точнее, реплики синхронизации) записали сообщение в свое постоянное хранилище.

Настройка производителя: acks = all

Долговечность самая высокая. Задержка примерно в 2,5 раза больше, чем у лидера.

С точки зрения производителя это можно рассматривать как доставку хотя бы один раз, поскольку сообщения никогда не теряются (но могут быть доставлены повторно).

Как проблема двух генералов может повлиять на Kafka Producer?

Теперь, как мы знаем из проблемы 2 Генералов, когда Генерал не получает подтверждение, он не знает, не удалось ли само сообщение или подтверждение не удалось. Чтобы быть уверенным в доставке, оно отправляет сообщение несколько раз, что приводит к дублированию сообщений.

Аналогично, когда производитель Kafka настроен на получение подтверждений, и если он не получает подтверждения, у него нет другого выбора, кроме как повторно отправить сообщение. Если сообщение уже написано брокером и отсутствует только подтверждение, это может привести к дублированию сообщений. Следовательно, это приводит к тому, что сообщения доставляются потребителю более одного раза.

Что можно сделать, чтобы избежать дублирования сообщений?

Прежде всего, дублирующиеся сообщения могут быть проблемой, а могут и не быть. Если требуются схемы Exactly Once, производитель Kafka поддерживает опцию идемпотентной доставки, которая гарантирует, что повторная отправка не приведет к дублированию записей. Это позволяет производителю повторять попытки до тех пор, пока они не будут успешными, без возможности дублирования.

Кафка прозрачно обнаруживает и игнорирует их. Для этого брокер присваивает каждому производителю идентификатор и выполняет дедупликацию сообщений, используя порядковый номер, который отправляется производителем вместе с каждым сообщением.

С точки зрения производителя, это схемы «Ровно один раз».

Идемпотентному производителю необходимы acks = all и другие ограничения для настроек Retries и MaxInFlight.

Важно. Чтобы узнать поведение по умолчанию, ознакомьтесь с документацией SDK для конкретного языка. Для Java это верно по умолчанию в версии ≥ 3.0.0 KAFKA-10619. Включить идемпотентность производителя по умолчанию.

Но для .NET по умолчанию отключено https://docs.confluent.io/platform/current/clients/confluent-kafka-dotnet/_site/api/Confluent.Kafka.ProducerConfig.html#Confluent_Kafka_ProducerConfig_EnableIdempotence.

Сводка

  1. 2 Generals» — задача, демонстрирующая проблемы распределенных вычислений из-за возможных сбоев. Прагматичные решения проблемы учитывают этот факт и пытаются его смягчить.
  2. Производитель Kafka предлагает 3 вида гарантии доставки.
  3. При отсутствии подтверждения производитель Kafka может создавать дубликаты сообщений. Если нужна схема ровно один раз, ее можно включить. Проверьте SDK для конкретного языка на предмет поведения по умолчанию.

Надеюсь, вам понравилась статья. В следующем я расскажу о гарантиях доставки для потребителя.

Справочная информация и дальнейшее исследование

2 Задача генералов — https://finematics.com/two-generals-problem/

Гарантии Kafka Producer — https://developer.confluent.io/courses/architecture/guarantees/