Kafka на 94 % диска, 17 часов в запасе и retention, который хранил вдвое больше
Трафик вырос в 150 раз, а тома никто не пересматривал. Хуже того, при дефолтном роллинге сегментов retention в 7 дней на деле означал 7–14. Как мы выиграли время и устранили причину.
В Gambchamp сработал алерт: Kafka забивает свои тома. Вопрос был обычный — потерпит ли до утра?
Не потерпело бы. Все три брокера стояли на 36,6 из 39,1 ГиБ, 94 %. Рост в среднем 3,37 ГиБ в сутки и до ~5 ГиБ в сутки в вечерний пик. Оставалось примерно 17 часов, то есть диск закончился бы посреди ночи, прямо в пик. Следующая автоматическая очистка retention ожидалась только через двое суток.
Ничего не сломалось
Причин было две, и ни одна не была поломкой.
Трафик вырос примерно в 150 раз. С ~5 сообщений в секунду в начале августа до плато ~780 сообщений в секунду после запуска продукта. Lag у консьюмеров нулевой, ошибок в логах брокеров нет, under-replicated партиций нет. Тома по 40 ГиБ просто проектировались под другую нагрузку.
Retention на деле был 7–14 дней, а не 7. В конфиге брокеров retention не задавался вовсе, работали дефолты Kafka: log.retention.hours=168 и log.roll.hours=168, сегменты по 1 ГиБ. Retention удаляет только закрытые сегменты. Наши партиции набирали несколько сотен мегабайт в неделю и до 1 ГиБ не дорастали, поэтому сегмент закрывался по 7-дневному таймеру — и только тогда у него начинался отсчёт retention. Отсюда «пила» на графике диска: большой сброс раз в неделю, между зубцами не освобождается ничего.
Практический вывод: такой том нельзя планировать как «7 дней × скорость». С такими дефолтами — 14.
Выигрываем время
Тома были на расширяемом классе gp3, поэтому первый шаг — онлайн-расширение PVC с 40 до 100 ГиБ. Без рестартов, без under-replicated партиций, GitOps-приложение осталось синхронным — PVC создаются из volumeClaimTemplates и в Git их нет, так что self-heal нечего было откатывать. Сразу 100, а не 60, потому что AWS разрешает модифицировать том не чаще раза в шесть часов.
Устраняем причину
На следующий день выяснилось, что retention в 7 дней — реальное требование архитекторов бэкенда. Это перевернуло смысл фикса: система не недодерживала, а хранила почти вдвое больше требуемого. Роллинг сегментов раз в 12 часов (log.roll.ms=43200000) возвращает реальное удержание к 7–7,5 дням, не трогая log.retention.hours.
При прогнозе роста в 4 раза стационар выходил ~185 ГиБ как есть против ~99 ГиБ с 12-часовыми сегментами, поэтому целевой том стал 200 ГиБ. Пропускная способность, IOPS, файловые дескрипторы и CPU были далеко от пределов — потолок был в объёме, а не в производительности.
Три ловушки по дороге
- Неверный ключ, на который ответили «Completed». Сначала мы выставили
log.segment.ms— такой настройки у брокера нет (на уровне топика она называетсяsegment.ms).kafka-configs.shответилCompleted updating default configи ничего не поменял. Правильное имя —log.roll.ms, а что реально действует, показывает только--describe --all. - Динамический override перекрывает файл. Динамический конфиг брокера приоритетнее
server.properties. Пока override не снят, значение в Git декоративно — а если снять его слишком рано, роллинг ненадолго вернётся к 168 часам. - «Безопасное» пересоздание StatefulSet’а перезапустило все брокеры. В живом pod template осталась старая аннотация
kubectl.kubernetes.io/restartedAt, которой не было в рендере из Git, — хэш изменился, и все брокеры прокатились. По одному, штатно, но незапланированно.
После изменений: тома по 200 ГиБ заняты на 21 %, всё приходит из Git, сегменты роллятся дважды в сутки.
Выводы
- Время до заполнения считайте по пиковой скорости и сравнивайте со следующим сбросом retention. Если сброс позже — ждать нельзя.
- Требование, совпавшее с дефолтом, — это незаписанное требование. Задавайте retention явно, даже если значение равно дефолтному.
kafka-configs.shсообщает об успехе и для неизвестных ключей. Проверяйте через--describe --all.- Перед
delete sts --cascade=orphanпроверьте, нет ли в pod template аннотацииrestartedAt.