Что такое партиция (partition) и зачем она нужна
Представьте почтовое отделение с несколькими окнами:
🟢 Junior Level
Что такое партиция?
Партиция (Partition) — это «под-канал» внутри топика. Каждая партиция — это упорядоченная, неизменяемая последовательность сообщений, которая постоянно дополняется.
Зачем партиции: механизм параллелизма. Одна партиция = один консьюмер может её читать. Если бы топик был одним целым, только один консьюмер мог бы работать. Партиции позволяют N консьюмерам читать один топик одновременно.
Аналогия
Представьте почтовое отделение с несколькими окнами:
- Топик — это всё почтовое отделение
- Партиции — это отдельные окна обслуживания
- Каждое окно обслуживает свою очередь клиентов независимо
- Клиенты в одной очереди обслуживаются строго по порядку
Topic "orders"
┌─────────────┬─────────────┬─────────────┐
│Partition 0 │Partition 1 │Partition 2 │
│ msg-0 │ msg-0 │ msg-0 │
│ msg-1 │ msg-1 │ msg-1 │
│ msg-2 │ msg-2 │ msg-2 │
└─────────────┴─────────────┴─────────────┘
Зачем нужны партиции?
- Параллелизм — каждая партиция читается одним консьюмером. 10 партиций = 10 консьюмеров работают параллельно
- Масштабирование — партиции распределяются по разным брокерам
- Отказоустойчивость — каждая партиция реплицируется на несколько брокеров
Простой пример
# Создание топика с 3 партициями
kafka-topics.sh --create \
--topic orders \
--partitions 3 \
--replication-factor 3 \
--bootstrap-server localhost:9092
3 партиции, 3 консьюмера:
Consumer 1 → читает Partition 0
Consumer 2 → читает Partition 1
Consumer 3 → читает Partition 2
🟡 Middle Level
Анатомия партиции
Offset — порядковый номер каждого сообщения внутри партиции. Уникален только в рамках одной партиции.
Partition 0:
offset=0 {"userId": 1, "action": "login"}
offset=1 {"userId": 2, "action": "purchase"}
offset=2 {"userId": 1, "action": "logout"}
Ordering — строгий порядок только внутри одной партиции. Глобального порядка в топике не существует.
Immutability — сообщения нельзя изменить или удалить выборочно. Удаление происходит целыми сегментами.
Репликация партиций
Partition 0 на кластере из 3 брокеров:
Broker A → Leader (принимает read/write)
Broker B → Follower (копирует с Leader)
Broker C → Follower (копирует с Leader)
- Чтение и запись всегда идут через лидера
- Фолловеры пассивно копируют данные
- При падении лидера один из фолловеров становится новым лидером
ISR (In-Sync Replicas)
ISR = множество реплик, которые «догнали» лидера
Leader: offset=100
Follower B: offset=100 → в ISR
Follower C: offset=95 → НЕ в ISR (отстаёт)
ISR = {Leader, Follower B}
Выбор количества партиций
| Фактор | Рекомендация |
|---|---|
| Throughput продюсера | partitions >= producer_throughput / per_partition_throughput |
| Throughput консьюмера | partitions >= consumer_throughput / per_consumer_throughput |
| Запас на рост | Умножайте на 2-3 |
Как данные распределяются по партициям
partition = hash(key) % numPartitions // если есть ключ
partition = round-robin / sticky // если ключа нет
Типичные ошибки
| Ошибка | Последствие | Решение |
|---|---|---|
| Одна партиция | Нет параллелизма | Минимум 3-6 партиций |
| Слишком много партиций | Нагрузка на контроллер, память, FD | Рекомендуется не более 2000-4000 на брокер для стабильной работы. Технический предел — ~200 000 (KRaft), но производительность контроллера деградирует. |
| Добавление партиций «на лету» | Нарушение порядка ключей | Планируйте заранее |
| Неравномерное распределение | Hot partition | Проверяйте распределение ключей |
Добавление партиций
kafka-topics.sh --alter --topic orders --partitions 10
Последствия:
- Старые данные не перераспределяются — остаются в старых партициях
- Новые сообщения попадают во все партиции
hash(key) % Nменяется → те же ключи попадают в другие партиции → порядок нарушается
🔴 Senior Level
Внутреннее устройство партиции
На уровне кода Kafka каждая партиция представлена объектом Partition в ReplicaManager. Физически партиция — это набор сегментных файлов на диске:
/var/kafka-logs/orders-0/
├── 00000000000000000000.log # Segment 0, data
├── 00000000000000000000.index # Segment 0, sparse index (offset → physical position)
├── 00000000000000000000.timeindex # Segment 0, time-based index (timestamp → offset)
├── 00000000000000000000.txnindex # Segment 0, transaction index
├── 00000000000000100000.log # Segment 1 (rotated at segment.bytes)
├── 00000000000000100000.index
├── 00000000000000100000.timeindex
├── leader-epoch-checkpoint # Для предотвращения data loss при смене лидера
└── __txn_index__.0 # Transaction metadata (если включены транзакции)
Log Segments — детали
segment.bytes=1GB # Ротация по размеру
segment.ms=7 дней # Ротация по времени
segment.jitter.ms=0 # Случайная задержка для избежания thundering herd
index.interval.bytes=4096 # Частота записей в индекс
Sparse Index: Индекс не для каждого сообщения, а каждые index.interval.bytes байт. Это делает индекс компактным (~1 запись на 4KB данных). Поиск: бинарный поиск по индексу → линейное сканирование в сегменте.
Leader/Follower Replication Protocol
Replica Fetcher Thread (на каждом Follower):
1. Send FetchRequest → Leader
2. Leader возвращает batch с current leader epoch
3. Follower записывает в свой лог
4. Обновляет LEO (Log End Offset)
5. Leader обновляет HW (High Watermark)
High Watermark (HW) = последний offset, подтверждённый всеми ISR
Messages с offset > HW — не видны консьюмерам
LEO (Log End Offset) — номер последнего записанного сообщения.
HW (High Watermark) — номер последнего сообщения, подтверждённого всеми репликами. Консьюмеры видят только сообщения до HW.
Leader Epoch: Введён в Kafka 0.11 для устранения data loss при смене лидера. Хранится в leader-epoch-checkpoint файле. При failover новый лидер обрезает лог до последнего подтверждённого epoch.
ISR (In-Sync Replicas) — глубинный механизм
Условия нахождения в ISR:
replica.lag.time.max.ms=30000 // Follower должен «догонять» за 30 секунд
replica.fetch.wait.max.ms=500 // Максимальное ожидание fetch request
Replica State Machine:
NewReplica → OnlineReplica → Leader/Follower → OfflineReplica → NonExistentReplica
OSR (Out-of-Sync Replicas): Реплики, отставшие от лидера. Не учитываются при min.insync.replicas.
KRaft Mode (Kafka Raft Metadata)
До KRaft: ZooKeeper хранил метаданные кластера (топики, партиции, контроллер, ISR).
С KRaft (Kafka 3.3+ production-ready):
Controller Quorum (odd number, min 3 nodes):
- Хранит метаданные в __cluster_metadata topic
- Raft consensus protocol вместо ZK
- Устраняет ZK как SPOF
- Быстрее обработка изменений метаданных
- Поддержка до 200 000 партиций (vs 200 000 с ZK с деградацией)
metadata.log.segment.bytes=100MB
metadata.log.segment.ms=1 день
metadata.max.retention.bytes=100MB
Edge Cases (3+)
-
Unclean Leader Election: При
unclean.leader.election.enable=trueout-of-sync реплика может стать лидером → потеря данных (сообщения между HW старого лидера и LEO нового будут потеряны). Для финансовых систем всегдаfalse. -
Split-Brain при KRaft: Если кворум контроллеров теряет большинство (например, 2 из 5 узлов упали), кластер не может менять метаданные (создавать топики, выбирать лидеров). Чтение/запись существующих партиций продолжают работать.
-
Log Divergence при Network Partition: Если лидер и фолловер разделены сетью, лидер продолжает запись. При восстановлении связи фолловер усекается до HW лидера. Если HW ещё не обновился — возможна потеря подтверждённых продюсером сообщений (при
acks=1). -
Metadata Propagation Delay: В больших кластерах (10K+ партиций) обновление метаданных (новый топик, новая партиция) может занимать 30-60 секунд. Продюсеры/консьюмеры получают stale metadata и отправляют сообщения в неправильные брокеры (NotLeaderForPartitionException).
-
Disk Failure on Single Replica: Если диск с партицией вышел из строя, ISR уменьшается. Если
min.insync.replicasне достигнут — продюсеры сacks=allполучаютNotEnoughReplicasException. Kafka не восстанавливает данные автоматически с других брокеров — требуется ручное вмешательство.
Performance Numbers
| Метрика | Значение | Условия |
|---|---|---|
| Throughput на партицию | ~50-100 MB/s | SSD, batch.size=256KB, lz4 |
| Max partitions/broker | ~200 000 | KRaft, 64GB RAM, SSD |
| Recommended partitions/broker | 2 000-4 000 | Для стабильной работы |
| Replication lag (нормальный) | < 100 ms | В пределах одного AZ |
| Leader election time | 5-30 секунд | Зависит от unclean.leader.election |
| Segment flush interval | log.flush.interval.messages=9223372036854775807 (OS flush) |
Production War Story
Ситуация: E-commerce платформа с 50 партициями на топик
orders. После добавления 50 партиций (итого 100) для масштабирования, клиенты начали жаловаться на «потерянные» заказы и дубликаты в обработке.Корневая причина: При увеличении партиций
hash(key) % 50изменился наhash(key) % 100. События одного заказа попали в разные партиции. Сервис обработки заказов собирал события по ключу, но теперь «создание заказа» было в партиции 23, а «оплата» — в партиции 73. Обработчик платежа не нашёл исходный заказ.Дополнительная проблема: 100 партиций × 3 реплики × 5 брокеров = 600 файловых дескрипторов только на один топик. Начались
Too many open filesошибки.Решение:
- Создали новый топик
orders-v2со 100 партициями- Dual-write: продюсеры писали в оба топика 72 часа — продюсеры отправляли сообщения одновременно в старый и новый топик, 72 часа, чтобы консьюмеры могли дочитать старые данные из первого и начать читать новые из второго.
- Консьюмеры переключились на
orders-v2- Увеличили
ulimit -nс 4096 до 65536- Включили
log.retention.check.interval.ms=300000для своевременной очистки сегментовУрок: Никогда не добавляйте партиции в топик, если используете ключи для гарантий порядка. Создавайте новый топик и мигрируйте трафик.
Мониторинг (JMX + Burrow)
JMX метрики партиций:
kafka.cluster:type=Partition,name=UnderReplicated
kafka.cluster:type=Partition,name=InSyncReplicasCount
kafka.server:type=ReplicaManager,name=IsrShrinksPerSec
kafka.server:type=ReplicaManager,name=IsrExpandsPerSec
kafka.log:type=Log,name=LogEndOffset,partition=0
kafka.log:type=Log,name=LogStartOffset,partition=0
kafka.log:type=Log,name=Size,partition=0
Burrow (consumer-centric):
- Lag per partition — детализация до уровня партиции
- Status: OK, WARN, ERR, STOP, STALL
- HTTP API → Grafana → PagerDuty
Highload Best Practices
- Планируйте партиции заранее — их нельзя уменьшить без пересоздания топика
- Формула:
partitions = max(prod_throughput, cons_throughput) / per_partition_capacity * 1.5 - Не более 4000 партиций на брокер — иначе деградация контроллера
- Используйте KRaft для новых кластеров — быстрее metadata propagation, нет ZK dependency
- Мониторьте ISR Shrink/Expand — индикатор проблем репликации
- Segment sizing:
segment.bytesподбирайте так, чтобы сегмент закрывался за 1-4 часа - OS tuning:
vm.dirty_background_ratio=5,vm.dirty_ratio=10для flush control - Disk: SSD обязательны для production. NVMe для high-throughput (>50 MB/s на партицию)
🎯 Шпаргалка для интервью
Обязательно знать:
- Партиция — механизм параллелизма: 1 партиция = 1 консьюмер
- Порядок гарантирован строго внутри одной партиции (FIFO)
- Offset — порядковый номер сообщения, уникален только в рамках партиции
- Каждая партиция реплицируется: Leader (read/write) + Followers (copy)
- ISR — реплики, синхронизированные с лидером; лидер выбирается только из ISR
hash(key) % N— при добавлении партиций распределение ключей меняется- Уменьшение партиций невозможно; добавление нарушает порядок по ключу
- Рекомендуемый максимум: 2000-4000 партиций на брокер
Частые уточняющие вопросы:
- Что будет при добавлении партиций? — Старые данные не перераспределяются; ключи попадут в другие партиции → порядок нарушен.
- Что такое High Watermark? — Последний offset, подтверждённый всеми ISR. Консьюмеры видят только до HW.
- Можно ли уменьшить партиции? — Нет, только удалить и создать топик заново.
- Что такое Leader Epoch? — Номер поколения лидера; предотвращает data loss при смене лидера.
Красные флаги (НЕ говорить):
- «Порядок гарантирован во всём топике» — только внутри партиции
- «Можно уменьшить партиции» — невозможно
- «Offset уникален глобально» — уникален только в партиции
- «Добавление партиций безопасно при использовании ключей» — нарушает порядок
Связанные темы:
- [[1. Что такое топик (topic) в Kafka]]
- [[3. Как данные распределяются по партициям]]
- [[17. Что такое leader и follower реплики]]
- [[18. Что такое ISR (In-Sync Replicas)]]
- [[28. Как удаляются старые сообщения из топика]]