Зачем Kafka: журнал вместо отчёта

Kafka и альтернативы: когда она не нужна

16 мин
Чему научишься
  • собирать очередь из одной таблицы и одного запроса
  • брать свободные строки и молча пропускать те, что в эту секунду держит сосед
  • называть, что умеет брокер очередей и чего у журнала нет совсем
  • отвечать на три вопроса выбора — и посчитать по ним свой эфир, где ответ выходит обратный

09:20. Шесть сообщений в сутки

2 ноября 2184 года. Диспетчерская уровня связи «Хранилища-9». Стойка гудит, эфир идёт ровно. И тебя накрывает энтузиазм: раз эфир уже работает, давай пустим через него вообще всё. В том числе уведомление «в проявочной кончилась плёнка». Таких уведомлений шесть в сутки.

КВЕРИ, не открывая глаз, выкатывает на панель журнал прошлой смены. Такой топик уже был — film_out, шесть сообщений в сутки.

Пять лет назад, 14 марта, его консьюмер — программа, которая забирала уведомления и звала людей, — упал в 02:10. Заметили в 06:30 — когда смотритель пришёл и увидел, что проявочная стоит. Четыре часа двадцать минут никто ничего не знал.

Почему никто не заметил? Жив ли консьюмер, проверяли по одному числу — по лагу: сколько сообщений он ещё не прочитал. У топика на шесть сообщений в сутки мёртвый консьюмер выглядит точно так же, как живой: лаг — ноль. За ночь в топик не пришло ни одного сообщения, первое ждали только к полудню. Датчик молчал ровно потому, что кричать было не о чем.

КВЕРИ: Я помню имена топиков, которых больше нет. Этот закрыли не из-за Kafka.

Почему закрыли весь уровень, КВЕРИ не говорит: «Спроси меня, когда у тебя впервые пропадёт подтверждённая запись». Сегодня вопрос другой — нужна ли плёнке вообще Kafka.

Дежурный со спины вынимает одну строку из голографической таблицы на шесть строк. Позади тянется огромная лента конвейера — почти пустая, на ней одна капсула. КВЕРИ, кот-интерфейс архива, сидит на краю ленты.
Шесть сообщений в сутки: мёртвый консьюмер выглядит так же, как живой.
Сначала альтернатива — в настоящем PostgreSQL. dsp_queue — таблица-очередь: одна строка — одно задание, а колонка status говорит, свободно оно или его уже кто-то взял. Работник w1 забирает три самых старых свободных задания ОДНИМ оператором. FOR UPDATE SKIP LOCKED здесь главное: запрос берёт свободные строки и молча пропускает те, что в эту секунду держит другой работник, — вместо того чтобы стоять и ждать его.

Очередь — это таблица и один запрос

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

Где такая таблица сдаётся? На большом потоке: каждое взятое задание — запись в базу, выполненные строки потом убирает , и к десяткам тысяч сообщений в секунду база работает на одну очередь. И там, где одно сообщение нужно сотне получателей: строку забирает кто-то один. Для этого существуют брокеры очередей — RabbitMQ и родня. Брокер очередей — посредник: держит сообщение у себя, пока получатель не подтвердит его, а неподтверждённое отдаёт другому. Подтвердил — сообщение у брокера исчезло.

Не путай с брокером Kafka: так зовут одну машину её кластера — ту, что держит журналы на своём диске. Поэтому RabbitMQ и родню дальше называем двумя словами — «брокер очередей».

Чего журнал не умеет в принципе

От очереди чаще всего хотят одного: повторить ОДНО неудачное сообщение. Журнал этого не умеет. Консьюмер помнит не список сделанного, а одно число на партицию — оффсет, до которого дочитал. Записать этим числом «всё до восьмого готово, кроме четвёртого» нельзя. Поэтому, когда обработчик падает на четвёртом сообщении из восьми, выходов три, и все платные:

  • назад — вернуть позицию: четвёртое пойдёт снова, но пятое–восьмое будут ждать, партиция стоит;
  • вперёд — сдвинуть позицию: группа пропустит четвёртое навсегда — в журнале оно лежит, но группа к нему уже не вернётся;
  • в сторону — переложить четвёртое в отдельное место и идти дальше: семь из восьми сделаны, одно ждёт человека.
Повторить именно четвёртое в обычной группе не выразить, поэтому бесплатного выхода у журнала нет. Брокер очередей повторяет сообщения по одному, но платит за это порядком.

Три вопроса выбора

Теперь у тебя есть обе цены, и выбор решают три вопроса:

вопросесли ответ такойчто берёмчем платим
сколько систем получают одно событие?однатаблицу-очередь или брокер очередейисторию не перечитать
нужно повторять сообщения по одному?даочередь, не журналпорядок не сохраняется
сколько данных и как быстро нужен ответ?мало, минуты не критичнытаблицу-очередь в своей базена росте упрёшься в базу
film_outодна система, повтор по одному, 6 в суткитаблицу-очередьничем: база уже есть

Для плёнки ответ очевиден: одна таблица в базе, которая уже есть. Kafka там была лишней — и именно поэтому её мёртвый консьюмер прятался за нулём.

А теперь те же вопросы про наш эфир

Сначала одно слово. Системы, которым уходит эфир, зовём потребителями эфира: сегодня это Читальный зал, за смену их станет шесть. Не путай с консьюмером: консьюмер — программа, которая читает топик, а потребитель эфира — тот, кто пользуется результатом.

Задаём те же три вопроса — и ответ выходит обратный:

  • у одного сообщения эфира много потребителей эфира, и у каждого свой темп;
  • повтора по одному не нужно: сообщение, которое не разобралось, откладываем в сторону, и эфир идёт дальше;
  • данных много, и они идут без перерыва: таблица-очередь в базе на таком потоке задохнётся. А срок годности ответа у Читального зала — 30 секунд. Вчерашняя лента давала худший возраст 30 ч 12 мин, часовой прогон дал бы 64 минуты, а поток даёт 1,2 секунды — это числа из ячейки урока «Пакетный отчёт или поток: сколько ждёт ответ», ты их сам печатал.

И то, чего у таблицы-очереди нет вовсе: прочитанное из журнала не исчезает — его можно перечитать, а из того же журнала можно собрать справочник. Об этом — уроки «Топик — это журнал: сегменты и срок хранения» и «Компакция: по ключу остаётся последнее». Вот здесь Kafka на своём месте — и это видно по числам.

Одна оговорка на будущее: в Kafka 4 часть сценариев очереди закрыта иначе, чем в этом уроке (подробно — урок «Share groups: Kafka как очередь» в треке «Углублённо»).

Что в этом уроке настоящее, а что нет

Запрос с FOR UPDATE SKIP LOCKED — настоящий PostgreSQL. Но двух работников сразу в одной ячейке не запустить, поэтому гонку за строки ты не видишь — только форму запроса и результат. То, что второй работник получит другие три задания, — правило PostgreSQL: мы его называем, но не показываем.

Три исхода упавшего сообщения показаны диаграммой, без прогона: они прямо следуют из того, что позиция в группе одна на партицию. Режим Kafka 4 из оговорки выше здесь тоже не запускается — учебная Kafka покажет его в уроке «Share groups: Kafka как очередь» из трека «Углублённо».

Вопрос с собеседования

Как это спрашивают на собеседовании

Самый частый вопрос: «Kafka или RabbitMQ?» Худший ответ — «Kafka быстрее»: он показывает, что разницы моделей кандидат не понимает.

Хороший ответ начинается с двух встречных вопросов: сколько разных систем-адресатов у одного события и нужно ли переотправлять отдельное сообщение. Много адресатов, у каждого свой темп, нужно перечитывать историю — Kafka. Один исполнитель, повтор по одному, приоритеты, отложенная доставка — брокер очередей (message broker: RabbitMQ, ActiveMQ, NATS JetStream).

Второй вопрос: «А когда вы бы не стали брать брокер очередей вовсе?» Ждут таблицу-очередь в базе, которая уже есть, и честную оценку, до какой нагрузки её хватит. Индустриальное имя приёма — SELECT … FOR UPDATE SKIP LOCKED, сама таблица — queue table.

Третий вопрос появился недавно: «Изменилось ли что-то в Kafka 4?» Изменилось — часть сценариев очереди теперь закрывает сама Kafka. Отвечать «Kafka — это не очередь, и точка» уже неполно (подробно — урок «Share groups: Kafka как очередь» в треке «Углублённо»).

Проверь себя
Проявочная присылает шесть уведомлений в сутки, исполнитель у них один, и неудачное уведомление нужно повторить отдельно, не трогая остальные. База на уровне уже есть. Что взять?
Главное из урока
задачачто берёмпочему
уведомления проявочной, 6 в суткитаблица-очередь в своей базеадресат один, повтор по одному
эфир двенадцати антеннKafkaпотребителей эфира много, свой темп у каждого, ответ нужен за 30 с

Очередь — это одна таблица и один запрос: FOR UPDATE SKIP LOCKED берёт свободное и пропускает занятое. Брокер очередей повторяет сообщения по одному, журнал — не умеет: позиция в группе одна на партицию. Kafka нужна там, где у события много адресатов и история читается заново.

КВЕРИ: Плёнку оставь базе. А эфир — нам. Вечером посмотрим, где он лежит на самом деле.