Модуль 31. Autoscaling и оптимизация ресурсов
Цель: добиться предсказуемой производительности и стоимости: поды получают ровно столько CPU/памяти, сколько нужно, реплики появляются до того, как пользователи видят деградацию, а узлы кластера не простаивают.
Итог после внедрения:
- Для stateless/интерактивных сервисов и воркеров — HPA (по CPU/памяти/метрикам из Prometheus/KEDA).
- Для «подбора размеров» подов — VPA (как рекомендатель или «initial»).
- Для эластичности инфраструктуры — Cluster Autoscaler с node groups (в т. ч. spot/preemptible) и приёмами overprovisioning.
- Requests/limits и QoS выставлены осознанно; риски oversubscription и OOM под контролем.
Карта автомасштабирования: кто за что отвечает
- HPA (Horizontal Pod Autoscaler): меняет количество подов в Deployment/StatefulSet по метрикам.
- VPA (Vertical Pod Autoscaler): рекомендует/меняет requests/limits пода.
- Cluster Autoscaler (CA): добавляет/убирает узлы в node group, чтобы поды могли уместиться.
- KEDA (по ситуации): HPA «по событиям» (очереди/лаг), scale-to-zero.
- Они работают в связке: HPA увеличивает реплики → CA добавляет узлы; VPA помогает корректно задать запросы, чтобы HPA «видел» реальную нагрузку.
HPA для сервисов и воркеров
Что важно на практике
- Метрики: CPU/Memory (metrics-server) или кастомные (через Prometheus Adapter) — RPS, p95 latency, ошибки, Kafka lag.
- Границы: minReplicas и разумный maxReplicas (с учётом бюджетов БД/внешних API).
- Поведение: behavior.scaleUp/scaleDown (окна стабилизации, шаги в % или pod). Снимает «пилу».
- Readiness/Startup Probes: без них HPA может считать «ручку» здоровой раньше времени → холодные поды «забивают» SLA.
Мини-эскиз (идея):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
minReplicas: 3
maxReplicas: 30
metrics:
- type: Resource
resource: { name: cpu, target: { type: Utilization, averageUtilization: 60 } }
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies: [{ type: Percent, value: 100, periodSeconds: 60 }]
scaleDown:
stabilizationWindowSeconds: 300
policies: [{ type: Percent, value: 20, periodSeconds: 60 }]
BI/DWH-примеры:
- Trino воркеры — HPA по длине очереди/занятости слотов (custom metric), ограничить maxReplicas под бюджет координирующей БД/S3.
- Airflow/Kafka воркеры — KEDA по lag/глубине очереди (ScaleObject/ScaledJob).
- HTTP-BI (Superset/Metabase) — HPA по RPS, p95 latency или CPU (в зависимости от профиля).
VPA: как использовать без конфликтов с HPA
-
Режимы: Off/RecommendOnly, Initial, Auto. В проде часто:
- RecommendOnly — собираем рекомендации и вносим их вручную/GitOps (без рестартов пода),
- или Initial — подставляет requests один раз при создании пода (дальше HPA рулит репликами).
-
Нельзя одновременно давать VPA менять CPU/Memory и строить HPA по CPU-utilization: изменения requests сдвигают базу для HPA → «качели».
Решение: VPA только рекомендации/initial, а HPA строить по внешним метрикам (RPS/lag) или зафиксировать requests и давать HPA работать по CPU.
Эскиз VPA-рекомендателя:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
spec:
targetRef: { apiVersion: "apps/v1", kind: Deployment, name: app }
updatePolicy: { updateMode: "Off" } # только рекомендации
Cluster Autoscaler и пулы узлов
-
Node groups: разделите по типам нагрузки — general, batch, gpu, spot.
Настройте min/max на группу, типы инстансов, диски. - CA scale-up: когда есть pending-поды, которые не умещаются. Поддержите это: у подов должны быть requests, а у групп — подходящая конфигурация (taints/labels/instance types).
- CA scale-down: через время простоя узла; блокировки: PDB, DaemonSet без префикса, «булавки» (под в состоянии без эвакуируемости).
- Overprovisioning: Deployment с «пустыми» подами низкого приоритета (pause-образ, PriorityClass: very-low). CA держит «горячую» ёмкость; при прибытии реальных подов — эти «пустышки» вытесняются. Хорошо для интерактивного BI.
Spot/Preemptible узлы: дешево, но аккуратно
-
Где уместно: stateless, воркеры (Trino/Spark), ETL, кэш, вторичные реплики.
Не ставим: primary БД, Zoo/Keeper-подобные координационные узлы, критичный control-plane. -
Стратегия надёжности:
- Смешивайте on-demand + spot (под по nodeAffinity/preferredDuring…), таинтите spot-пул (spot=true:NoSchedule) и только нужным подам добавляйте toleration.
- Разнообразие типов/АЗ увеличивает стабильность спота.
- Реагируйте на termination notice (preStop hook, быстрый drain, сокращение terminationGrace только там, где безопасно).
- PDB и реплики — обязательны, чтобы выдержать внезапную вырубку.
Requests/Limits и QoS: от этого зависит всё
- Requests — «гарантия» при планировании; Limits — «потолок» (для CPU — CFS-throttling; для памяти — OOMKill).
-
QoS классы:
- Guaranteed: requests == limits по всем ресурсам → стабильность при давлении.
- Burstable: есть requests, но limits выше/отсутствуют — компромисс.
- BestEffort: нет requests → первыми «вылетают» при давлении.
- Память: не oversubscribe. Для прод-сервисов лучше: requests=limits (Guaranteed) или хотя бы requests с запасом и без жёсткого memory-limit, если у приложения хороший self-limit (редко).
- CPU: можно упруго — часто ставят requests < фактической пиковой, а limit=∞ (или =requests на чувствительных к джиттеру JVM). Следите за throttling (Prometheus container_cpu_cfs_throttled_seconds_total).
Практика тюнинга:
- Снимите p50/p95/p99 потребления на стабильной неделе.
-
Requests ≈ p50–p70, limits:
- для интерактива/JVM: = requests (минимум джиттера) или небольшой headroom;
- для воркеров/ETL: limit можно поднять/убрать, но QoS останется Burstable.
- Пересматривайте раз в 1–2 месяца или по «сигналам» (throttling/OOM/недобор).
Память, OOM и эвикции: как не «стрелять себе в ногу»
- Причины OOM: limit слишком мал, спайк alloс, фрагментация, JVM/GC настройки, буферы нативных либ.
-
Митигируем:
- закладывайте headroom (10–30% к p95),
- для JVM: согласуйте Xmx/MaxRAM% с k8s-limit, учтите off-heap/Metaspace;
- не ставьте минимальные limits на «долгоиграющие» процессы (pgBouncer, координатор Trino);
- включите eviction thresholds на нодах разумно; следите за node allocatable и system-reserved/kube-reserved.
- Диагностика: события OOMKilled, Evicted причины, метрики container_memory_working_set_bytes, page cache, dmesg; стройте алерты на rate OOM.
Приоритеты, PDB и стратегия обновлений
- PriorityClass: критичным системным/BI-шлюзам — высокий приоритет; batch — низкий. Это влияет на preemption.
- PDB защищают минимальное число реплик при drain/spot-выбросах/обновлениях.
- RollingUpdate/MaxUnavailable/MaxSurge должны быть согласованы с HPA и PDB (иначе «не обновляется/не масштабируется»).
Наблюдаемость и алертинг по автоскейлу
- HPA: desired vs current replicas, врезание в maxReplicas (SLO-риск), длительная «пила» scaleUp/Down.
- VPA: разница между текущими requests и рекомендациями.
- CA: время ожидания pending-подов, частота масштабирования, неиспользуемые узлы.
- Спотовый пул: частота прерываний, недоступность зон/типов.
- SLO: p95 latency/ошибки бизнес-операций; алерты burn-rate + «HPA упёрся в max».
Практика (лабораторка 1–2 дня)
- HPA для HTTP-сервиса: по CPU (60%) + поведение (scaleUp/Down). Проверить на нагрузке график latency → добиться плавности.
- VPA RecommendOnly: собрать рекомендации за неделю; через GitOps обновить requests.
- CA + два пула: on-demand (general) и spot (batch). Настроить taints/tolerations, PriorityClass, PDB.
- Overprovisioning: развернуть «пустышки» низкого приоритета для быстрого scale-in/scale-out.
- KEDA для воркеров: масштабировать по lag очереди; ограничить maxReplicaCount.
- Аналитика OOM/Throttling: дашборд и алерты по OOMKilled и cpu_throttled_seconds.
Риски и анти-паттерны
|
Риск |
Проявление |
Что делать |
|---|---|---|
|
Oversubscription памяти |
OOM/Evicted, лавина рестартов |
Requests с запасом, Guaranteed для критичных, headroom на нодах |
|
CPU-throttling |
Джиттер, рост p95, timeouts |
Для чувствительных сервисов limit≈request, а лучше без limit (под контролем), следить за throttling |
|
HPA↔VPA конфликт |
«Качели», масштабирование «не туда» |
VPA в RecommendOnly/Initial; HPA по внешним метрикам |
|
HPA упёрся в max |
Рост latency/ошибок |
Увеличить maxReplicas или добавить узлы (CA), оптимизировать код/кэш |
|
CA не скейлит |
Pending-поды «висят» |
Есть ли requests? Подходят ли taints/labels? PDB/DaemonSet блокируют? |
|
Спот «сыпется» |
Потеря подов |
Микс on-demand+spot, PDB, разнообразить типы, termination-hooks |
|
Нет PDB/приоритетов |
Апгрейд «роняет» SLA |
Ввести PDB/PriorityClass, согласовать с rollout-стратегиями |
|
Неверные probes |
HPA думает, что всё ок |
Пробы на реальную готовность (прогретые кэши/соединения) |
Чек-лист «готово к продакшену»
- HPA включён для интерактивных и воркерных сервисов; поведение (stabilization/policies) настроено.
- VPA в RecommendOnly/Initial; процесс регулярного применения рекомендаций через GitOps.
- Cluster Autoscaler работает; пулы разделены (general/batch/gpu/spot), taints/tolerations/labels выстроены.
- Requests/limits выставлены по данным (p50–p95), QoS для критичных — Guaranteed.
- Для batch — отдельный пул, низкий PriorityClass, ResourceQuota.
- PDB/PriorityClass/rollout-настройки согласованы.
- Мониторинг: HPA/CA/VPA/Spot/Throttling/OOM; алерты «HPA=max», «OOM rate», «pending>Х мин».
- Документы: runbook’и «всё упёрлось в max», «шторм OOM», «прерывания spot», «CA не скейлит».
Вопрос-ответ
В: Можно ли одновременно использовать HPA по CPU и VPA в Auto?
О: Не стоит. VPA меняет requests → HPA «плывёт». Комбинация безопасная: HPA (по CPU/внешним метрикам) + VPA RecommendOnly/Initial.
В: Как выбрать целевую утилизацию CPU для HPA?
О: Отталкивайтесь от точки, где p95 latency ещё в норме. Часто 50–70%. Проведите нагрузочный тест и зафиксируйте.
В: Нужны ли limits по CPU?
О: Для критичных к джиттеру JVM-сервисов — часто limit=request (QoS Guaranteed). Для batch — limit можно ослабить/убрать, но следите за суммарной утилизацией и throttling.
В: Как бороться с резкими всплесками трафика?
О: Overprovisioning (pause-pods), уменьшить stabilizationWindow для scale-up, держать «тёплые» поды, оптимизировать cold-start (образ/инициализация).
В: Что масштабировать в Trino/ClickHouse?
О: Trino — воркеры по queue/slots, хранение — отдельно. ClickHouse — реплики/шарды масштабируют «вширь», но это плановая операция, а не «каждую минуту HPA».
В: Стоит ли использовать spot в проде?
О: Да, но только для не критичного состояния (воркеры, кэши) и в смеси с on-demand. Убедитесь, что реплик и PDB достаточно.
В: Как понять, что requests выставлены неверно?
О: Признаки: частые OOM/eviction (занижена память), постоянный throttling (занижен CPU), HPA «пилит» без стабилизации, CA при этом скучает (завышены requests).
Рабочий автоскейл — это не один HPA-манифест, а система: метрики, VPA-рекомендации, пулы узлов и CA, осознанные requests/limits (QoS), PDB/приоритеты и продуманный спот. Тогда поды масштабируются до того, как страдает SLA, счета за инфраструктуру остаются под контролем, а инциденты «OOM/не влезло» превращаются в редкость, а не в рутину.



