Привет! Меня зовут Антон Губарев, я инженер PaaS (Platform-as-a-Service) в Авито. Платформа как сервис позволяет продуктовым командам разработки не тратить время на рутинные и инфраструктурные задачи, например, определение оптимальных значений request/limit CPU и RAM для контейнеров в кластерах Kubernetes. Вместо этого они могут сосредоточиться на качестве сервиса, над которым работают. PaaS умеет автоматически рассчитывать ограничения и выделять ресурсы для каждого сервиса.
Рассказываю, как мы в Авито собираем метрики потребления ресурсов серверного оборудования, храним и используем их, чтобы спланировать потребление в будущем.
Решения для сбора метрик и анализа потребления ресурсов
Все сервисы Авито выкатываются в 3–4 независимых кластера Kubernetes и весь влетающий трафик балансируется между ними. Сервис в продакшене существует в каждом кластере. Взаимодействие осуществляется через наш Service Mesh, в том числе и между кластерами если это необходимо. Всего мы используем несколько десятков кластеров под разные нужды, и они периодически сменяют друг друга: один выводится из эксплуатации и вместо него вводится другой.
При таком количестве сервисов и кластеров важно понимать, сколько ресурсов оборудования мы тратим на текущие задачи и сколько понадобится при масштабировании в будущем. Для этого мы регулярно собираем и анализируем метрики:
Потребление CPU и RAM глобально на все сервисы суммарно.
Потребление CPU и RAM на каждый контейнер/под, чтобы можно было выявить аномалии.
Суммарное потребление по деплойментам.
Индекс потребления (Resource Volume) как единая метрика, понятная для руководства.
Раньше для сбора метрик и мониторинга мы использовали Prometheus, но со временем его возможностей перестало хватать. Поэтому перешли на VictoriaMetrics. Это база данных для хранения временных рядов, которая поддерживает протокол PromQL.
VictoriaMetrics отлично кластеризуется и меньше тормозит на тех же объёмах данных. Переход на новое решение позволил снизить потребление ресурсов CPU примерно в семь раз, а RAM — в 12 раз.
При этом осталась задача, которую VictoriaMetrics решить не может в наших условиях: долгосрочная аналитика и планирование потребления. Недостаточно данных за семь дней, нужна информация за месяцы и кварталы. А хранить такие объемы без серьезной потери производительности не позволяли возможности ни VM, ни Prometheus.
В качестве решения для хранения данных за длительный период мы выбрали ClickHouse. Это OLAP-система, которая способна переваривать большие объемы. Предварительные эксперименты показали, что ClickHouse может не только хранить, но и быстро отдавать данные за нужные нам периоды..
Ещё у ClickHouse есть интересные фичи:
Материализованные представления — аналог View в РСУБД.
Словари — хранилище внешних данных в виде пар «ключ-значение». Доступ к ним происходит быстрее, чем с помощью JOIN-ов.
Какие данные о потреблении мы храним
Главные метрики, которые нас интересуют: глобальный расход CPU и RAM, расход на каждый контейнер или под и общий индекс потребления Resource Volume.
Сначала разберёмся с метриками для CPU/RAM. С точки зрения аналитики нас интересует фактическое потребление — usage, и запрошенные ресурсы — request, для сервиса за минуту, день, неделю и месяцы. Основная таблица хранения в ClickHouse:
CREATE TABLE resources.consumption
(
time DateTime,
namespace String,
env LowCardinality(FixedString(10)),
cluster LowCardinality(FixedString(20)),
deployment String,
pod String,
node String,
unit Nullable(String),
cpu_usage Nullable(Float64),
cpu_request Nullable(Float64),
mem_usage Nullable(UInt64),
mem_request Nullable(UInt64),
net_tx_usage Nullable(UInt64),
net_tx_usage Nullable(UInt64)
)
engine = ReplicatedMergeTree()
PARTITION BY toYYYYMM(time)
ORDER BY (time, namespace, env, cluster, deployment, pod, node)
SETTINGS index_granularity = 8192;
Мы написали сборщик данных, который аккумулирует данные из всех экземпляров VictoriaMetrics и переносит их в ClickHouse, контролирует доступность источников. С его помощью сделали первую выгрузку данных за полгода. Получили больше 15 миллиардов записей, при этом аналитические запросы длились от 10 секунд — это долго.
Чтобы улучшить производительность, решили использовать материализованные представления и просуммировать данные по подам до уровня микросервиса. Этого достаточно для аналитических запросов и планирования потребления. Для суммирования использовали движок SummingMergeTree, который присутствует в ClickHouse.
CREATE TABLE resources.consumption
(
time DateTime,
namespace String,
env LowCardinality(FixedString(10)),
cluster LowCardinality(FixedString(20)),
deployment String,
pod String,
node String,
unit Nullable(String),
cpu_usage Nullable(Float64),
cpu_request Nullable(Float64),
mem_usage Nullable(UInt64),
mem_request Nullable(UInt64),
net_tx_usage Nullable(UInt64),
net_tx_usage Nullable(UInt64)
)
engine = SummingMergeTree(
pods, cpu_usage, cpu_request, mem_usage, mem_request, net_tx_usage, net_rx_ usage)
PARTITION BY toYear(time)
ORDER BY (env, cluster, namespace, time)
SETTING ingex_granularity = 8192
Запрос, с помощью которого данные из таблицы-источника автоматически переносятся в материализованное представление:
SELECT
time,
namespace,
env,
cluster,
count() AS pods,
sum(cpu_usage) AS cpu_usage,
sum(cpu_request) AS cpu_request,
sum(mem_usage) AS mem_usage,
sum(mem_request) AS mem_request,
sum(net_tx_usage) AS net_tx_usage,
sum(net_rx_usage) AS net_rx_usage
FROM resources.consumption
GROUP BY
env,
cluster,
namespace,
time
Новая выгрузка данных за полгода дала около 2 миллиардов записей, а аналитические запросы стали занимать меньше секунды.
Ещё одна важная метрика — Resource Volume (RV). Она показывает общую картину потребления ресурсов в компании и нужна больше для менеджмента. 1 RV — это эквивалент 1 CPU или 3 ГБ RAM. Допустим, у сервиса есть 10 реплик, каждая из которых потребляет 1 CPU и 2 ГБ RAM. Значит, всего сервис использует 10 CPU и 20/3 RAM, или 16,6 RV.
Как отображаются аналитические данные о потреблении ресурсов
Аналитика потребления отображается в формате графиков и диаграмм в Grafana.
Отдельный дашборд с данными за несколько месяцев есть в PaaS. Внутри него можно посмотреть детализацию потребления до пода. Можно быстро проверить, сколько ресурсов потребляет каждый сервис, и сразу увидеть аномалию.
На основе аналитики в PaaS мы построили систему бюджетирования ресурсов. Команды, которые используют общие ресурсы, объединены в юниты. Каждый юнит раз в квартал подаёт заявку на выделение для него серверных мощностей. Одобренные заявки и использованная часть ресурса отображаются в дашборде.
Юниты отслеживают, какую часть ресурса они уже использовали. Если ресурсов недостаточно, например, юнит не учёл масштабирование, можно подать новую заявку досрочно.
Запрос ресурсов и ограничения
Кроме мониторинга потребления нужно правильно распределить ресурсы между сервисами. Для этого мы автоматически считаем, сколько ресурсов он запрашивает и какими лимитами ограничен.
В Kubernetes можно установить значения request и limit для CPU и RAM для каждого контейнера. Причём разработчики Авито делают это не вручную, а только указывают с помощью PaaS, сколько реплик сервиса им нужно. Система деплоя распределяет их по кластерам, в том числе рассчитывает request и limit.
Расчёт проходит в четыре шага, на каждом из которых значения request/limit могут измениться.
Первый шаг / Box. Для каждого языка программирования, которые используются в Авито, и для каждого размера сервиса есть предустановленные — «коробочные» — значения. Размер может быть большой, средний или маленький, его указывает в конфигурации разработчик, когда создаёт сервис (может быть изменено в любой момент). Языки, для которых есть предустановленные значения, — Go, PHP, Python, JavaScript, Kotlin и Swift. Например, для маленького сервиса на Go можно запросить максимум 100 CPU.
Второй шаг / Usage. Для расчёта значений request/limit на этом шаге используется 75 перцентиль за три дня и постоянный коэффициент Ratio. Данные по потреблению хранятся в VictoriaMetrics, среднее значение берётся по всем кластерам, где запущен сервис.
Например, если сервис за прошлые 3 дня потреблял в среднем 500 RAM, то значение request для него будет равно 1 000 (Ratio=2), а limit — 5 000 (Ratio=10).
Третий шаг / Range. Для исключения вероятности бесконтрольного роста значений request/limit и возможности появления аномалий мы установили некоторые пороговые значения, больше или меньше которых значения выставиться не могут. —
На этом шаге платформа проверяет каждый контейнер и корректирует request/limit, если они вышли за максимальное или минимальное значения. Даже если один из микросервисов ведёт себя аномально и потребляет слишком много ресурсов по историческим данным (Usage), это не повлияет на выделение ресурсов в новом деплое. При возникновении таких ситуаций разработчики разбираются в проблеме и исправляют ее, чтобы потребление пришло в норму.
Четвёртый шаг / Manual. В случае, когда автоматические расчёты не подходят, разработчик может выставить значения request/limit вручную. Например, если запускается высоконагруженный и критически важный микросервис, для которого нужны особые условия. Для этого есть специальный конфигурационный файл, в котором описывается, сколько реплик должно быть, какие переменные окружения, кроны и воркеры. Ещё в нём можно указать значения request/limit для крона, воркера или самого сервиса. Этот файл использует PaaS, когда разворачивает сервис. В конфигурационном файле разработчик вручную может прописать необходимые значения request и limit
[[envs.prod.crons]]
name = "import services consumption"
enabled = true
schedule = "*/5 * * * *"
command = 'etl -type=consumption -duration=1h'
resources/requests.cpu = 1000
resources.requests.memory = 10000
resources.limits.cpu = 5000
resources.limits.memory = 30000
На этом заканчивается работа автоматики, и микросервис раскатывается в нужное количество кластеров с нужными значениями ресурсов.
Что даёт мониторинг потребления ресурсов
Мы собираем полные данные по использованию ресурсов за год по всем сервисам и юнитам, поэтому точно знаем, кто и сколько потребляет. На основании этой информации можно долгосрочно планировать, например, для масштабирования в будущем.
В любой момент мы можем найти причину утечки ресурсов, если один из сервисов ведёт себя аномально. Вся информация за последнюю неделю хранится в VictoriaMetrics, а данные можно детализировать до каждого контейнера.
Разработчики не должны думать об устройстве инфраструктуры и запросе ресурсов. PaaS автоматически выставляет объективные значения request и limit для CPU и RAM. При этом в особых случаях можно прописать их вручную в конфигурационном файле.
Предыдущая статья: Как мы улучшили типографику на сайте Авито
mkevac
На сайте VictoriaMetrics среди фич написано "Long-term Storage for Metrics". Можете пояснить почему вы говорите что возможности VM не позволяют хранить метрики за долгий срок?
antgubarev Автор
На наших объемах информации хранить конечно можно, но вот время выполнения аналитических запросов уже не удовлетворяет.