Thanos и remote_write: когда 90 дней метрик Prometheus перестают помещаться
Разобрали Thanos как способ долгосрочного хранения метрик Prometheus через remote_write в object storage - и поняли, что это другая архитектура, не просто плагин.
Thanos - проект для долгосрочного хранения метрик Prometheus, анонсированный сообществом как open-source решение поверх object storage
Prometheus справляется с оперативным мониторингом очень хорошо. Это не комплимент из вежливости - он реально работает: scrape, TSDB, alerting, PromQL. Но у него есть физическое ограничение, которое рано или поздно становится разговором с заказчиком: локальный диск. Данные за 90 дней, несколько тысяч метрик, несколько инстансов - это быстро превращается в дискуссию про NVMe или в решение о том, что старше двух недель нам не нужно. Ни то ни другое нас не устраивало.
Когда в прошлом году сообщество анонсировало Thanos как open-source проект для долгосрочного хранения поверх object storage, мы решили смотреть внимательно.
Что за зверь Thanos
Thanos - это не fork Prometheus и не замена ему. Это несколько компонентов, которые встраиваются рядом и берут на себя то, что Prometheus не делает: репликацию данных в object storage, глобальный query layer поверх нескольких инстансов, и downsampling для длинных временных горизонтов.
Архитектура примерно такая:
graph LR
P1[Prometheus 1] -->|remote_write| SW1[Thanos Sidecar 1]
P2[Prometheus 2] -->|remote_write| SW2[Thanos Sidecar 2]
SW1 -->|upload TSDB blocks| S3[(Object Storage)]
SW2 -->|upload TSDB blocks| S3
S3 --> STO[Thanos Store]
SW1 --> QR[Thanos Querier]
SW2 --> QR
STO --> QR
QR -->|PromQL| GR[Grafana]
Thanos Sidecar запускается рядом с каждым Prometheus-ом. Он делает две вещи: открывает gRPC endpoint для Thanos Querier (чтобы тот мог ходить за свежими данными напрямую в TSDB), и периодически заливает закрытые TSDB-блоки в object storage. Thanos Store читает из object storage и отвечает на запросы Querier по старым данным. Querier склеивает всё в единый PromQL endpoint - Grafana смотрит на него как на обычный Prometheus.
Важная деталь: remote_write здесь используется не для передачи данных в object storage напрямую. Thanos Sidecar работает с TSDB-блоками - он читает файлы, которые Prometheus пишет локально, и загружает их когда блок закрывается (обычно каждые 2 часа). Remote_write - это другой путь, который Prometheus поддерживает параллельно и который можно направить куда угодно. В нашем случае мы использовали оба подхода: Sidecar для основного хранения, remote_write для дублирования в тестовый Cortex для сравнения.
Как разворачивали
Тестировали на managed-проекте с несколькими Prometheus-инстансами в Kubernetes. Задача: один из инстансов уже собирал метрики несколько месяцев, хотелось не потерять историю и добавить возможность смотреть на данные за полгода.
Thanos Sidecar добавляется как дополнительный контейнер в StatefulSet с Prometheus. Конфигурация минимальная - нужно дать ему S3-совместимый endpoint и credentials, указать директорию с данными Prometheus. Мы использовали Minio как S3-совместимое хранилище (в кластере уже стоял для других нужд), но в production имеет смысл смотреть на облачный S3 или аналог - хранить метрики там же где сами серверы не всегда правильно.
Thanos Querier разворачивается отдельно и получает список sidecar endpoint-ов через --store параметры. Для него нужен Ingress или NodePort - это новый endpoint для Grafana.
Thanos Store - ещё один Deployment, который умеет читать объекты из S3 и отдавать их в формате, понятном Querier. Ему нужен persistent volume для кеша (иначе при каждом запросе он будет тянуть данные из S3 заново, что медленно).
Что сразу бросилось в глаза: Querier умеет дедуплицировать метрики от нескольких Prometheus-инстансов, если они собирают одно и то же. Это решает проблему HA - можно запустить два Prometheus-а с одинаковыми scrape configs, и Thanos Querier покажет единый ряд без дублей. Мы не тестировали это всерьёз, но в демо-режиме работает правильно.
Где споткнулись
Версионирование компонентов. Thanos - молодой проект, версии sidecar, querier и store должны быть совместимы. Мы поставили разные версии из-за невнимательности - gRPC контракт не совпал, Querier не мог достучаться до Sidecar. Ошибка диагностировалась не очевидно: в логах было что-то про несовместимые protobuf версии, а не прямая надпись «версии не совпадают».
Labels deduplication. Querier дедуплицирует по label replica. Это нужно явно добавлять в external_labels Prometheus-а. Если не добавить - дедупликация не работает, получаешь задвоенные ряды в Grafana, начинаешь думать что сломал конфигурацию, хотя это просто отсутствующий label.
Downsampling не бесплатный. Thanos Compactor - отдельный компонент, который делает downsampling и compaction. Без него объекты в S3 копятся как есть: каждые 2 часа новый блок. Когда смотришь на год данных через Querier без compaction - это медленно, потому что Store честно читает все блоки по одному. Compactor мы поставили, но надо понимать что он должен быть только один - если запустить несколько Compactor-ов на одни данные, они будут конфликтовать.
Где сейчас
Thanos пока работает на одном проекте как пилот. Данные за несколько месяцев уходят в Minio, Grafana смотрит на Querier без изменений в дашбордах - это приятно, не пришлось переписывать ни одного запроса. Исторические данные из S3 отвечают медленнее чем из локального TSDB, но для аналитики за квартал это приемлемо.
Compactor запущен с суточным расписанием. Downsampling на 5m и 1h включен - старые данные из S3 возвращаются в Grafana быстрее.
Главный вывод пока: это не «поставил и забыл». Thanos требует понимания всех своих компонентов и того, как они взаимодействуют. Но если задача - хранить метрики дольше нескольких недель без покупки очень большого диска, альтернативных подходов почти нет.
- ArgoCD 0.x: GitOps-контроллер для Kubernetes, первое знакомство · 14 января 2019
- Kubernetes RBAC-харденинг: убираем wildcard-биндинги и включаем audit-log · 10 января 2019