Система обрабатывала около 10 миллионов событий в сутки с пиковыми всплесками до 18 тысяч событий в секунду. В статье описано, как была спроектирована архитектура на Apache Kafka, какие шаги привели к стабильной работе и какие метрики помогли обнаружить узкие места.
Задача и архитектура
Цель: обеспечить приём, буферизацию и обработку 10 000 000 событий в сутки (ключевая фраза для SEO: kafka 10 миллионов событий) с задержкой обработки менее 30 секунд для 95% событий и гарантией доставки «по крайней мере один раз». Проект стартовал в августе 2025 года, этапы внедрения завершались до марта 2026 года.
Входные события — телеметрия от мобильных приложений и backend-сервисов, средний размер сообщения — 1,2 КБ, пиковая нагрузка (short burst) — до 18 000 сообщений/сек, средняя нагрузка за сутки ≈ 116 сообщений/сек. Существенная характеристика — сильно выраженная пиковая активность в рабочие часы и пиковые пользовательские акции.
Архитектура базируется на следующем стеке:
- Apache Kafka 3.6 на продакшн-кластере (5 брокеров, each 24 CPU cores, 256 GB RAM, NVMe storage) — развернуто в декабре 2025.
- ZooKeeper заменён KRaft в тестовом кластере; на проде использовали Kafka с KRaft на этапе миграции в феврале 2026.
- Производители — микросервисы на Java/Scala и часть на Go; используются async-продюсеры с бафферизацией и батчингом.
- Консьюмеры — несколько consumer group, реализованные на Java (Kafka Clients 3.6) и Python (confluent-kafka), обрабатывают поток в режиме stream и batch.
- Мониторинг — Prometheus + Grafana (JMX Exporter на брокерах), алерты через Alertmanager; логирование — ELK/Elastic Stack.
- Отправлено: ~10 000 000 сообщений/сутки (~12 ГБ данных/сутки при среднем 1,2 КБ на сообщение)
- Пиковая TPS: до 18 000 сообщений/сек (короткие всплески 5—20 секунд)
- Средняя задержка записи в топик: 10–40 мс
Шаг 1: шардирование
Основная задача шардирования — обеспечить достаточный уровень параллелизма и избежать «горячих» партиций при пиковых нагрузках. Для kafka 10 миллионов событий в сутки ключевым было правильно подобрать количество партиций и схему ключирования.
Выбор числа партиций
Мы провели нагрузочные тесты в сентябре 2025: синтетические данные с тем же распределением ключей показали, что для устойчивой обработки всплесков до 18k msg/s оптимально иметь 150–300 партиций на основной топик. Итоговое решение — 200 партиций с replication.factor=3. Обоснование:
- 200 партиций обеспечивают нужную параллельность для 50–200 консьюмеров в группе.
- Масштабирование: при росте нагрузки можно увеличить число партиций для новых топиков или при ретерегистрации топика в off-peak.
- Производительность диска: NVMe позволяла держать достаточно скорость записи/чтения при таком числе активных партиций.
Ключирование сообщений
Ошибка большинства — привязывать ключи к ограниченному набору значений, что создаёт «горячие» партиции. Мы использовали следующий подход:
- Первичный ключ — user_id; если user_id распределён равномерно, ключ используем 그대로.
- Для сценариев с возможными hot users — добавляли «salting»: хеш(user_id) % N, где N выбирали равным 8. Это равномерней распределяет большие потоки от одного пользователя между 8 шардов.
- Для событий типа metrics/aggregates — без ключа (round-robin) при необходимости обеспечить равномерную запись.
// Пример простого салтинга на Java
String key = String.valueOf(userId);
int salt = Math.abs(key.hashCode()) % 8; // 0..7
String partitionedKey = salt + "_" + key;
producer.send(new ProducerRecord<>(topic, partitionedKey, payload));
Кроме распределения по ключу, важно было контролировать максимальный размер партиций и периодически выполнять compact/cleanup по политике retention, чтобы не накапливать лишние данные.
Шаг 2: consumer group
При обработке kafka 10 миллионов событий факт наличия корректной consumer group архитектуры был критичен для параллельной обработки и для управления перезапусками. Ключевые моменты — размер группы, rebalance strategy и обработка ошибок.
Размер группы и параллелизм
Правило: количество активных консьюмеров в группе не должно превышать числа партиций. Для 200 партиций мы целились в 120–180 консьюмеров по необходимости перераспределяя загрузку между нескольких групп (streaming vs batch).
- Для latency-sensitive потоков — 120 консьюмеров, каждый консьюмер обрабатывал ~1–200 партиций в пике.
- Для тяжелых батчевых задач (aggregation, enrichment) — отдельная группа с 40 консьюмерами и отдельным топиком для промежуточных результатов.
Стратегии ребалансировки
Мы использовали новый CooperativeStickyAssignor (available в Kafka 3.x) для снижения времени остановки при ребалансах. Это позволило минимизировать «стопы» обработки при увеличении/уменьшении числа консьюмеров. Настройки клиентской стороны (пример для Java):
props.put("partition.assignment.strategy",
"org.apache.kafka.clients.consumer.CooperativeStickyAssignor");
props.put("max.poll.interval.ms", "300000"); // 5 мин, чтобы дольше было время на обработку
props.put("session.timeout.ms", "10000");
props.put("heartbeat.interval.ms", "3000");
Обработка ошибок и идемпотентность
Чтобы избежать дублирования при retry мы ввели:
- Идемпотентную обработку на уровне бизнес-логики (dedupe по event_id с TTL в Redis/HBase).
- Коммит offset'ов вручную после успешной обработки пачки сообщений: enable.auto.commit=false и commitSync()/commitAsync() в нужных местах.
- Политики retry с backoff: для transient ошибок делали до 5 попыток с экспоненциальным шагом и помещали неудачные события в DLQ (dead-letter topic) после N попыток.
// Пример на Java: ручной коммит после обработки batch
consumer.poll(Duration.ofMillis(1000));
try {
processBatch(records);
consumer.commitSync();
} catch (ProcessingException e) {
// логируем и отправляем в DLQ
}
Шаг 3: мониторинг lag
Мониторинг lag — один из важнейших индикаторов здоровья pipeline при kafka 10 миллионов событий: он показывает, успевают ли консьюмеры обрабатывать сообщения и где появляются узкие места.
Какие метрики отслеживали
- consumer_lag per partition (через JMX/Prometheus) — основной показатель.
- throughput (msg/s) per topic и per partition.
- end-to-end latency: time_produced → time_processed (помечаем timestamp в сообщении).
- broker_metrics: bytes_in_per_sec, bytes_out_per_sec, request_rate, under_replicated_partitions.
- GC/heap usage JVM у продюсеров и консьюмеров.
Инструменты и дашборды
Использовали Prometheus + Grafana с готовыми дашбордами, дописанными в 2026:
- Дашборд latency: percentile 50/95/99 end-to-end, пиковая задержка.
- Дашборд lag: heatmap по партициям, алерт при lag > 1 000 000 сообщений в топике или при росте lag более чем на 20% за 5 минут.
- Алерты: alert при under_replicated_partitions > 0, при high_disk_utilization > 85%, при persistent GC pause > 3s.
Пример правила в Alertmanager (схематично):
ALERT KafkaConsumerLagHigh
IF kafka_consumergroup_lag_sum{group="processor-group\
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…