ADG Оставить заявку
Блог DevOps 5 мин чтения

Prometheus 2.3: мигрировали с 1.x на 2.x - новая TSDB и WAL меняют картину

Перевели production-мониторинг с Prometheus 1.x на 2.3: хранилище сжалось вдвое, WAL закрыл потери метрик при перезапуске. Рассказываем как шла миграция.

Контекст момента

Prometheus 2.3 - улучшенная компактизация TSDB и снижение потребления памяти

Prometheus 2.x вышел ещё в конце 2017-го, но мы с переездом не торопились. Первая версия 2.x серии ломала обратную совместимость по хранилищу, конфиг alertmanager переписывался почти с нуля, и у нас не было желания разбираться с этим на живом продакшне в спешке. Дождались стабилизации, посмотрели на 2.2, потом на 2.3 - и в июне начали переезд.

Рассказываем что изменилось по делу, без разжёвывания changelog.

Почему вообще переезжать

В прошлогоднем посте про тюнинг мы описывали борьбу с потреблением памяти и объёмом диска в 1.7. Параметр -storage.local.memory-chunks был постоянным источником беспокойства: выставишь мало - OOM, выставишь много - система сидит в своп. Плюс после каждого рестарта Prometheus несколько минут не был готов: он восстанавливал состояние из checkpoint-файлов на диске, и в это время метрики не скрейпились или скрейпились в никуда.

Архитектура хранилища в 1.x - это chunks-файлы и series-файлы, которые Prometheus периодически уплотняет. Механизм рабочий, но compaction в 1.x делалась в одном потоке, блокировала запись, и при большом числе временных рядов заметно просаживала latency скрейпа.

Prometheus 2.x переписал хранилище на Fabian Reinartz: новая TSDB (отдельная библиотека, изначально влитая в 2.0) хранит данные блоками по 2 часа, которые потом сливаются в блоки большего размера. WAL (write-ahead log) пишет каждую входящую точку перед тем как она попадёт в memory-block. Это два независимых улучшения, которые вместе радикально меняют поведение системы.

Что получили по хранилищу

Разница по диску оказалась существеннее чем ожидали. На одном из managed-проектов с несколькими сотнями тысяч временных рядов - типичная картина для мониторинга Kubernetes-кластера с cAdvisor и node_exporter - объём данных за одинаковый период у Prometheus 2.3 оказался примерно вдвое меньше чем у 1.7. Это не маркетинговое «до 3x экономии», а то что мы реально намерили в конкретном случае.

Причина - новый алгоритм компрессии Gorilla (тот же что в Facebook's Gorilla paper, 2015) применяется агрессивнее. В 1.x compaction была ленивой и частичной; в 2.x блоки уплотняются полностью и финальный block иммутабелен - его больше не надо перезаписывать.

Потребление памяти тоже изменилось, хотя здесь картина немного иная. В 1.x большую часть памяти занимали chunks в памяти. В 2.x WAL и head-block держатся в памяти, а старые блоки на диске Prometheus читает через mmap. Это означает что при малых объёмах RAM цифра в top у Prometheus 2.x может выглядеть больше из-за mmapped-страниц, но реально рабочий RSS обычно меньше.

WAL и проблема потерянных метрик

В 1.x при перезапуске Prometheus восстанавливал состояние из checkpoint. Checkpoint записывался по расписанию, и всё что успело прилететь между последним checkpoint и моментом рестарта - терялось. При плановых обновлениях это было терпимо, при OOM-kill или ошибке ядра можно было получить дыру в метриках на 5-15 минут.

WAL в 2.x пишет каждую входящую точку на диск синхронно перед подтверждением. При старте Prometheus replays WAL и восстанавливает всё что не попало в завершённые блоки. На практике перезапуск стал занимать несколько секунд вместо нескольких минут - и без потерь.

Это особенно важно для алертов: в 1.x после рестарта мы периодически видели ложные срабатывания или, наоборот, пропуски алертов, потому что Prometheus не знал что было в потерянном окне. С WAL эта проблема ушла.

Как шла миграция

Данные 1.x в 2.x не читаются: хранилища несовместимы. Мы не мигрировали историю, а просто запустили новый Prometheus 2.3 рядом со старым, дали ему 2 недели набрать историю параллельно, потом переключили Grafana на новый datasource и остановили старый.

Две недели - это не какая-то магия, просто достаточный горизонт для наших дашбордов. Если retention важен, можно подождать дольше или экспортировать часть метрик через remote_read (в 2.x есть совместимый интерфейс).

Конфиг Prometheus между 1.x и 2.x менялся в нескольких местах:

  • *`storage.local.ушли полностью** - новая TSDB настраивается через--storage.tsdb.pathи--storage.tsdb.retention`.
  • alertmanager_url переехал в alerting.alertmanagers с более гибким синтаксисом.
  • rule_files теперь поддерживают glob - это мелочь, но приятно.
  • federation и remote_write остались совместимы - конфиг не трогали.

Конфиг alertmanager - отдельная история: формат изменился сильно, но в нашем случае конфиги были несложные и переписались за час.

Компактизация в 2.3 конкретно

Prometheus 2.3 вышел в конце мая 2018. Среди изменений - улучшения в процессе компактизации: лучший выбор блоков для слияния и сниженное потребление памяти во время compaction. В предыдущих 2.x compaction под нагрузкой иногда давала заметные спайки по памяти. В 2.3 это сгладили.

На нашем тестовом стенде с синтетической нагрузкой пик памяти при compaction в 2.3 был ощутимо ниже чем в 2.1, на которой мы проводили первые тесты. Цифры не приводим - слишком зависят от конкретного профиля нагрузки, лучше тестируйте под свою.

Итог

Переезд занял больше времени на подготовку, чем на само переключение. Параллельная работа двух экземпляров - стандартная предосторожность при смене хранилища без миграции данных. Новая TSDB заметно скромнее по диску и памяти, WAL закрыл потерю метрик при перезапусках, и это два реальных аргумента за переход, а не маркетинг.

Дальше смотрим в сторону Alertmanager 0.15, который вышел одновременно с Prometheus 2.3 и тоже подвергся переработке - но это уже отдельный разговор.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.