Kafka: архитектура и базовые принципы — Часть 1
Если посмотреть на архитектуру крупной IT-компании — Aviasales, Uber, Avito, Яндекс или Ozon — с большой вероятностью где-нибудь между сервисами окажется Kafka. Иногда аккуратно встроенная в платформу данных, иногда как критичный компонент, который все боятся трогать, потому что «оно же работает».
Kafka давно перестала быть просто брокером сообщений и стала фундаментом современных распределённых систем.
Эта серия статей — подробное руководство по Kafka. Мы не только разберём основные компоненты, но и поймём, почему Kafka настолько быстрая, как она обеспечивает отказоустойчивость и что нужно учитывать при проектировании production-потоков.
Серия ориентирована на современные версии Apache Kafka 3.x и 4.x. Базовые принципы —
Topic,Partition,Producer,Consumer,Offset,Consumer Group, репликация иretention— актуальны для обеих веток. Там, где речь идёт об эксплуатации кластера, я ориентируюсь на Kafka 4.x и KRaft, а не на устаревший ZooKeeper-режим.
Что такое Kafka
Apache Kafka — это распределённая платформа потоковой передачи событий (Distributed Event Streaming Platform).
Если говорить простыми словами, Kafka — это распределённый журнал событий: одни приложения записывают в него сообщения, а другие читают их в своём темпе. Большинство новичков представляет Kafka как обычную очередь, но это только часть картины. Правильнее думать о Kafka как о логе, куда новые записи постоянно добавляются в конец. Например:
----------------------------------
User Registered
Order Created
Payment Success
Email Sent
Product Viewed
Review Added
----------------------------------
Но этим её возможности не ограничиваются.
Kafka умеет:
- передавать данные между микросервисами;
- сохранять журнал событий для повторного чтения и восстановления;
- масштабироваться горизонтально под высокую нагрузку;
- выдерживать очень высокий поток сообщений;
- восстанавливаться после отказа серверов (в следующих частях мы размеберем детально)
Именно поэтому Kafka используют не только как очередь сообщений, но и как основу для событийных потоков между сервисами, аналитикой и хранилищами данных.
Проблема прямых вызовов между сервисами
Представим интернет-магазин.
Когда пользователь оформляет заказ, необходимо:
- списать деньги;
- уменьшить остаток товара;
- отправить письмо;
- начислить бонусы;
- обновить аналитику;
- отправить уведомление в мобильное приложение.
Самое очевидное решение выглядит так: сервис заказов вызывает каждый зависимый сервис напрямую.

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

Получается классическая проблема сильной связанности (tight coupling): один сервис знает слишком много о внутренних процессах других сервисов.
Любое изменение затрагивает множество команд и контрактов. Временная недоступность одного сервиса начинает ломать весь пользовательский сценарий, хотя сам заказ уже мог быть успешно создан.
С Kafka сервис заказов может не вызывать всех напрямую. Он публикует событие, а остальные сервисы самостоятельно подписываются на него и обрабатывают в своём темпе. Пусть вас не пугает эта схема — в следующих частях мы подробно разберём, как она работает внутри.

Такой подход даёт несколько преимуществ.
- Сервис заказов не знает, кто будет читать событие.
- Можно добавить новый сервис без изменения существующего кода.
- Если один из сервисов временно недоступен, остальные продолжают работать.
Именно эта слабая связанность сделала Kafka настолько популярной.
Когда Kafka действительно нужна
Важно понимать: любое усложнение архитектуры должно быть оправданным. Kafka часто пытаются использовать там, где она не нужна, и это быстро превращается в лишнюю операционную сложность.
Здесь хорошо работает принцип KISS: если задачу можно решить проще, лучше начать с более простой архитектуры. Если же у вас небольшой интернет-магазин, CRM на 20 пользователей, простой REST API, монолит без высокой нагрузки – то с вероятностью 100% внедрение Kafka будет просто выстрелом себе в ногу. Во многих случаях достаточно RabbitMQ, Redis Streams, фоновых задач или обычной PostgreSQL. Использование Kafka оправдано тогда, когда уже есть реальные требования к потоку событий, независимым потребителям, replay или масштабированию, а не просто желание взять технологию «на будущее».
Kafka отлично вам подойдет, если:
- данные должны читать множество сервисов;
- необходима асинхронная обработка;
- требуется переживать пики нагрузки;
- важен журнал всех событий;
- нужно иметь возможность воспроизвести события с какого-то момента;
- нагрузка достигает “миллионов сообщений”.
Фундаментальное отличие от очередей
В классической очереди сообщение исчезает после обработки.

В Kafka всё иначе. Consumer Group фиксирует позицию чтения: «мы прочитали до сообщения №15342».
Kafka хранит committed offset не в памяти consumer-а, а во внутреннем топике __consumer_offsets. Важно понимать, что позиция чтения относится к конкретной связке Consumer Group, Topic и Partition, а не ко всей группе целиком.
Сами записи остаются в логе до истечения retention, поэтому другая группа потребителей может прочитать их позже.

Тот же Consumer при необходимости может сбросить offset и прочитать историю заново. Именно это делает возможными:
- Event Sourcing — подход, при котором Kafka хранит не только текущее состояние объекта, а последовательность событий, которые к нему привели. Например: OrderCreated → PaymentReceived → OrderShipped. Текущее состояние можно восстановить, проиграв события по порядку.
- Replay — возможность повторно прочитать старые сообщения из Kafka. Consumer может изменить offset и заново обработать события. Полезно после исправления бага, изменения бизнес-логики или для построения нового представления данных из истории.
- Stream Processing — обработка событий в реальном времени по мере их поступления. Например: Kafka → Flink/Kafka Streams → агрегация платежей за последние 5 минут → новый Kafka topic. Используется для фильтрации, агрегации, enrichment, join’ов и вычислений над потоками.
- CDC (Change Data Capture) — перенос изменений из базы данных в Kafka. Например, Debezium читает PostgreSQL WAL/MySQL binlog и публикует INSERT/UPDATE/DELETE в Kafka. Другие системы могут реагировать на изменения БД без постоянного polling базы.
- Аналитические системы — Kafka часто выступает транспортным слоем между источниками данных и аналитическим хранилищем. Например: микросервисы → Kafka → ClickHouse. Это позволяет собирать большие потоки событий, независимо масштабировать producers/consumers и строить near-real-time аналитику.
Первые термины Kafka
Перед тем как разбираться с внутренним устройством, давайте познакомимся с основными сущностями, чтобы нам говорить на одном языке.
Broker — сервер Kafka. На нём хранятся данные, журналы сообщений и метаданные партиций. Обычно брокеров несколько: так кластер получает больше пропускной способности и лучше переживает отказы.
Producer — приложение, которое отправляет сообщения. Это может быть:
- backend;
- мобильное приложение;
- касса магазина;
- банкомат;
- IoT-датчик.
Topic — логическая категория сообщений. Producer пишет сообщение не на конкретный сервер, а в Topic. Дальше Kafka размещает запись в одной из партиций этого топика.
Например:
orderspaymentsnotificationsusers
Consumer — приложение, которое читает сообщения. Самый простой пример — сервис рассылки уведомлений по созданному заказу.
Последнее, что нужно знать на данный момент: Producer и Consumer не обязаны знать друг о друге напрямую. Их связывает Topic.
На этом месте остановимся. Базовые сущности уже на столе, теперь можно перестать смотреть на Kafka как на «ещё одну очередь» и перейти к механике.
В следующей части разберём Partition — механизм, который позволяет Kafka масштабироваться, не превращая порядок сообщений в лотерею. Затем рассмотрим Consumer Groups и соберём первую полноценную архитектуру Kafka.