Брокеры сообщений
Очереди сообщений и Kafka — компоненты, параллелизм партиций и консюмеров, ZooKeeper, очереди недоставленных сообщений и TTL.
10 вопросов
JuniorТеорияОчень частоЧто такое группа консюмеров в Kafka и что происходит при rebalance?
Что такое группа консюмеров в Kafka и что происходит при rebalance?
Группа консюмеров — консюмеры, делящие работу по топику: каждую партицию назначают одному участнику, поэтому каждое сообщение — один раз. Когда участник входит/выходит, Kafka запускает rebalance и переназначает партиции. Наивный rebalance останавливает группу; sticky-ассайнеры сокращают паузу.
Типичные ошибки
- ✗Думать, что каждый участник группы читает каждую партицию
- ✗Считать, что два консюмера в одной группе могут делить одну партицию
- ✗Не знать, что rebalance может останавливать потребление, пока партиции переезжают
Уточняющие вопросы
- →Почему добавление консюмеров сверх числа партиций оставляет часть из них без дела?
- →Как частые rebalance из-за мигающего консюмера бьют по пропускной способности?
JuniorТеорияОчень частоЧто такое брокер сообщений и из каких основных компонентов состоит очередь вроде Kafka или RabbitMQ?
Что такое брокер сообщений и из каких основных компонентов состоит очередь вроде Kafka или RabbitMQ?
Брокер сообщений развязывает продюсеров и консюмеров: продюсер публикует сообщение, брокер его хранит, а консюмер читает позже — так им не надо быть онлайн одновременно. Он также буферизует всплески для медленных консюмеров. Основные части — брокер (сервер, хранящий сообщения), продюсеры, консюмеры и очередь или топик. В Kafka топик делится на партиции; в RabbitMQ сообщения идут через exchange в очереди.
Типичные ошибки
- ✗Думать, что продюсер и консюмер должны быть онлайн одновременно
- ✗Путать брокер с балансировщиком или обычной базой данных
- ✗Не знать, что топик Kafka делится на партиции
Уточняющие вопросы
- →Как развязка продюсеров и консюмеров повышает устойчивость к пикам нагрузки?
- →Чем топик Kafka структурно отличается от очереди RabbitMQ?
MiddleТеорияЧастоУ топика Kafka 3 партиции, а группа консюмеров — 4. Хорошо или плохо? Чем занят ZooKeeper?
У топика Kafka 3 партиции, а группа консюмеров — 4. Хорошо или плохо? Чем занят ZooKeeper?
В одной группе консюмеров каждую партицию читает не более одного консюмера, так что при 3 партициях и 4 консюмерах один простаивает — потеря ёмкости, а не ошибка. Партиции — единица параллелизма, поэтому масштабируют добавлением партиций. ZooKeeper (в старом Kafka) ведёт координацию кластера — членство брокеров, выбор контроллера, метаданные; новый Kafka заменяет его встроенным кворумом KRaft.
Типичные ошибки
- ✗Думать, что несколько консюмеров в группе могут делить одну партицию
- ✗Масштабировать добавлением консюмеров сверх числа партиций
- ✗Считать, что ZooKeeper хранит данные сообщений, а не координирует кластер
Уточняющие вопросы
- →Как ключ партиционирования решает, в какую партицию попадёт сообщение?
- →Почему увеличение числа партиций задним числом ломает гарантии порядка по ключу?
SeniorТеорияЧастоЧто такое доставка at-most-once, at-least-once и exactly-once и как на деле достигается exactly-once?
Что такое доставка at-most-once, at-least-once и exactly-once и как на деле достигается exactly-once?
At-most-once теряет сообщение: коммит offset до обработки, и падение роняет то, что в полёте. At-least-once дублирует: коммит после обработки — падение переобрабатывает, прагматичный дефолт. Exactly-once — не флаг брокера: это at-least-once плюс идемпотентность/дедупликация (ключ идемпотентности).
Типичные ошибки
- ✗Считать exactly-once флагом брокера, а не идемпотентной обработкой
- ✗Путать, какой порядок коммита даёт at-most-once, а какой at-least-once
- ✗Считать at-least-once небезопасным, а не прагматичным дефолтом
Уточняющие вопросы
- →Почему коммит offset после обработки — это и есть механизм at-least-once?
- →Как ключ идемпотентности позволяет консюмеру безопасно поглотить дубликат?
SeniorТеорияЧастоКак Kafka обеспечивает надёжность и порядок в пределах партиции и что делают репликация и in-sync-реплики (ISR)?
Как Kafka обеспечивает надёжность и порядок в пределах партиции и что делают репликация и in-sync-реплики (ISR)?
Каждая партиция реплицируется на брокеры — один лидер, остальные фолловеры. In-sync-реплики (ISR) — это фолловеры, догнавшие лидера; при acks=all запись переживает потерю брокера, когда её приняли нужные реплики. Порядок гарантируется только внутри партиции, поэтому связанные сообщения кладут по ключу в одну партицию.
Типичные ошибки
- ✗Считать, что Kafka даёт глобальный общий порядок, а не порядок внутри партиции
- ✗Думать, что настройка acks тюнит только скорость, а не надёжность
- ✗Считать, что каждый брокер держит полную копию каждой партиции
Уточняющие вопросы
- →Почему партиция всё же теряет данные при acks=1, если лидер падает до копирования фолловерами?
- →Как добавление партиций позже ломает порядок по ключу, на который опирался существующий ключ?
JuniorТеорияИногдаЧто такое offset консюмера в Kafka и как консюмер продолжает работу после перезапуска?
Что такое offset консюмера в Kafka и как консюмер продолжает работу после перезапуска?
Offset — это позиция сообщения внутри партиции, монотонный индекс. Группа консюмеров коммитит обработанный offset, обычно во внутренний топик Kafka, поэтому при перезапуске продолжает с него, не с начала. Если offset ещё нет, политика auto-offset-reset — earliest или latest — задаёт, откуда начать.
Типичные ошибки
- ✗Думать, что сообщения помечает прочитанными брокер, а не консюмер ведёт offset
- ✗Считать, что перезапуск всегда перечитывает всю партицию с нуля
- ✗Путать закоммиченный offset с временной меткой по часам
Уточняющие вопросы
- →Как коммит offset до или после обработки меняет поведение при падении?
- →Почему каждая группа консюмеров ведёт свой независимый offset на одной партиции?
JuniorТеорияИногдаЧем лог-брокер вроде Kafka отличается от очереди вроде RabbitMQ и когда использовать каждый?
Чем лог-брокер вроде Kafka отличается от очереди вроде RabbitMQ и когда использовать каждый?
RabbitMQ — это очередь: сообщение уходит одному конкурирующему консюмеру и удаляется после ack, распределяя работу между воркерами. Kafka — это append-only лог, который консюмеры читают со своим offset, поэтому много групп перечитывают один хранимый поток. Очередь — для задач, лог — для стриминга.
Типичные ошибки
- ✗Думать, что Kafka удаляет сообщение, как только консюмер его прочитал, как очередь
- ✗Считать, что RabbitMQ хранит сообщения для повторного чтения, как лог
- ✗Считать выбор очередь-против-лога деталью реализации, а не решением дизайна
Уточняющие вопросы
- →Почему консюмер Kafka может перечитать вчерашние события, а консюмер RabbitMQ — нет?
- →Как конкурирующие консюмеры на очереди теряют порядок, который сохраняет партиция Kafka?
MiddleДебаггингИногдаЛаг группы консюмеров всё растёт и никогда не догоняет. Определите причину по выводу состояния группы.
Лаг группы консюмеров всё растёт и никогда не догоняет. Определите причину по выводу состояния группы.
Читайте лаг по партициям, не суммарно. У партиции 2 нет консюмера (CONSUMER-ID пуст): её лаг растёт безгранично — консюмеров меньше, чем партиций. Offset партиции 1 стоит: консюмер застрял на «отравленном» сообщении или медленный. Фикс: довести консюмеров до партиций и увести сообщение в DLQ.
Открыть задачу →Типичные ошибки
- ✗Смотреть только суммарный лаг и упускать одну застрявшую или непривязанную партицию
- ✗Добавлять партиции вместо консюмеров, когда группе не хватает участников
- ✗Считать, что Kafka пропускает «отравленное» сообщение, а не повторяет его вечно
Уточняющие вопросы
- →Почему партиция без назначенного консюмера копит лаг без ограничений?
- →Как коммит offset до обработки превращает «отравленное» сообщение в тихую потерю данных?
MiddleТеорияРедкоЧто такое dead-letter queue (DLQ) в брокере сообщений и что такое TTL сообщения?
Что такое dead-letter queue (DLQ) в брокере сообщений и что такое TTL сообщения?
DLQ — это отдельная очередь, куда попадают сообщения при сбое доставки — их отклонили, превышен лимит повторов или истёк срок — чтобы «отравленное» сообщение не блокировало основную очередь, а его можно было разобрать позже. TTL (time to live) — это срок жизни на сообщение или очередь: по истечении сообщение отбрасывается или уходит в DLQ. Вместе они держат очередь здоровой при сбоях.
Типичные ошибки
- ✗Думать, что сбойное сообщение молча удаляется без варианта DLQ
- ✗Путать TTL с минимальной задержкой, а не со сроком истечения
- ✗Не знать, что «отравленное» сообщение без DLQ может блокировать основную очередь
Уточняющие вопросы
- →Как лимит повторов/передоставок решает, когда сообщение уходит в DLQ?
- →Почему мониторинг глубины DLQ — полезный ранний сигнал в проде?
SeniorДизайнРедкоВы проектируете путь приёма событий для платёжной платформы. Топик Kafka должен принимать стабильно 100 000 сообщений в секунду с запасом на всплески 2x. Каждое событие несёт account_id, и все события одного аккаунта должны обрабатываться строго в порядке поступления, тогда как для событий разных аккаунтов порядок не важен. Один экземпляр консюмера обрабатывает около 5 000 сообщений в секунду, и нужно уметь наращивать мощность консюмеров по мере роста трафика без переобработки истории и без нарушения порядка по аккаунту. Опишите схему: сколько партиций вы заложите и почему, как ключуете сообщения, как масштабирование группы связано с числом партиций и что произойдёт с порядком по аккаунту, если позже увеличить число партиций.
Вы проектируете путь приёма событий для платёжной платформы. Топик Kafka должен принимать стабильно 100 000 сообщений в секунду с запасом на всплески 2x. Каждое событие несёт account_id, и все события одного аккаунта должны обрабатываться строго в порядке поступления, тогда как для событий разных аккаунтов порядок не важен. Один экземпляр консюмера обрабатывает около 5 000 сообщений в секунду, и нужно уметь наращивать мощность консюмеров по мере роста трафика без переобработки истории и без нарушения порядка по аккаунту. Опишите схему: сколько партиций вы заложите и почему, как ключуете сообщения, как масштабирование группы связано с числом партиций и что произойдёт с порядком по аккаунту, если позже увеличить число партиций.
Партиции берут под пик, а не под среднее: при ~5k msg/s на консюмера 100k требует ~20, берут ~40 с запасом. Ключ каждого события — account_id, чтобы события аккаунта шли в одну партицию. Группа масштабируется только до числа партиций, поэтому берут большим сразу: рост партиций позже перехэширует ключи и ломает порядок по аккаунту.
Типичные ошибки
- ✗Задавать число партиций под среднюю нагрузку, а не под пик с запасом
- ✗Считать, что консюмеры масштабируются сверх числа партиций
- ✗Не знать, что рост числа партиций ломает существующий порядок по ключу
Уточняющие вопросы
- →Почему хэш ключа в партицию чинит порядок по аккаунту, но не глобальный порядок?
- →Как бы вы добавили мощности позже без репартиционирования, перемешивающего ключи?