~/
~/

Contents

Тротлинг Go приложений в k8s

В этом посте разберемся с gomaxprocs и тротлингом go приложений в k8s

Note

Основная метрика при мониторинге контейнеров в k8s - trottling, она показывает сколько раз в момент времени тротлится ваш контейнер, в некоторых случаях мы можем видеть тротлинг, когда до лимитов cpu еще далеко, тогда откуда он берется?

K8s для реализации лимитов использует CFS Quota, настройки лимитов можно увидеть в файлах cfs_period_us и cfs_quota_us

Квота работает на периодах веремени:

cfs_period_us - задает продолжительность периода, это всегда 100мс
cfs_quota_us - задает доступное время внутри каждого периода

Таким образом получаем следующее:

---
resources:
  limits:
	cpu: 1000m = 100ms
	cpu: 500m  = 50ms
	cpu: 100m  = 10ms

Представим, что у нас есть приложение, которому для выполнения своей задачи необходимо 200мс процессорного времени, без лимитов график его работы выглядел бы следующим образом и тротлинга мы бы не увидели.

image

Теперь представим, что мы задали limits.cpu: 400m, приложению для его работы стало доступно только 40мс процессорного времени внутри каждого треда в 100мс, процесс ранее выполняющийся за 200мс теперь занимает 440мс

Приложение работает в течении 5 периодов по 100мс, в каждом из которых работает только 40мс, остальные 60мс тротлится.
Правильный лимит в таком случае составлял бы 2000m или его отсутствие :)

image

Note

Если с фундаментальным механизмом тротлинга понятно, то для приложений на go необходимо разобраться с горутинами

Для реализации параллелизма и возможности выполнения нескольких задач одновременно в go используются горутины
Главная особенность горутин состоит в том, что они могут выполняться параллельно, то есть на многоядерных архитектурах есть возможность выполнять отдельные горутины на отдельных ядрах процессора, тем самым горутины будут выполняться паралелльно, и программа завершится быстрее

В go есть возможность указать доступное колличество ядер для запуска горутин, для этого существует переменная GOMAXPROCS

Important

Значением по умолчанию для перменной GOMAXPROCS является общее колличество ядер доступных в системе ( Go 1.5 - Go 1.24)
В Go 1.25+ переменная имеет значение CPU limit контейнера (с округлением вверх до целого, минимум 2)

Таким образом Go приложение запущенное на сервере скажем с 96 ядрами и имеющее cpu.limit = 1000m, будет “видеть” все 96 ядер и попытается распределить на них нагрузку, в таком случае мы непременно получим большие значения тротлинга

Здесь у меня cert-manager имеющий limit = 100m, без явного GOMAXPROCS, имеется тротлинг порядка 60%

image

Поставим GOMAXPROCS = 1, тротлинг упал в 2 раза

image

Еще один пример, grafana, тут будет еще круче и наглядней :)

Графана имеет cpu.limit = 1500m и тротлится на 15%

image

Выставим GOMAXPROCS=1 и ужмем cpu.limit оставив только 1000m

image

Tip

Тротлинг упал до допустимых значений, в этом случае мы оптимизировали приложение да еще и съэкономили ресурсы кластера

Что можно сделать прямо сейчас?

  • Следите за GOMAXPROCS в ваших кластерах, старайтесь выставлять значения равные лимитам или около того
  • Если у вас есть возможность обновить версию Go до 1.25 или новее, это будет самым простым способом получить оптимальные настройки для контейнеров

fly save! =)