Что произойдет, если в Kubernetes поде лимит CPU 2 ядра, а скрипт использует все ядра
Что проверяют
Понимаете ли вы, чем лимит отличается от запроса ресурсов и как он реализован, и знаете ли главную ловушку Python в контейнере: библиотеки считают ядра ноды, а не то, что разрешено поду.
Как отвечать
Лимит не отбирает ядра, он задаёт квоту процессорного времени на период: два ядра это примерно двести миллисекунд на каждые сто миллисекунд периода. Скрипт может запустить работу хоть на всех ядрах ноды, но как только квота на период выбрана, все его потоки замораживаются до начала следующего. Это троттлинг: под не убивают и не перезапускают, в отличие от лимита памяти, где случится принудительное завершение. В метриках это рост числа придержанных периодов и рваная задержка ответа.
Питоновская часть важнее: os.cpu_count() и multiprocessing.cpu_count() возвращают ядра ноды, поэтому Pool() без аргумента поднимет на лимите в два ядра столько процессов, сколько ядер у машины. Быстрее не станет: та же квота делится на большее число процессов, добавляются память под интерпретаторы и переключения контекста. Так же ведут себя numpy и torch, они стартуют по потоку на ядро хоста.
Практика: число воркеров и переменные OMP_NUM_THREADS, OPENBLAS_NUM_THREADS, MKL_NUM_THREADS брать из лимита, прокинув его в под через downward API, либо читать квоту из cgroup. И помнить про GIL: на потоках все ядра не занять в принципе, ускорение дают процессы или расширения, отпускающие блокировку.
Где спотыкаются
Ждут, что под упадёт или перезапустится. Лимит процессора только замедляет, убивает превышение памяти. Из-за путаницы симптом читают неверно: контейнер жив, перезапусков нет, а проверки готовности отваливаются по таймауту.
Смешивают запрос и лимит. Запрос влияет на планировщик и на гарантию, лимит на троттлинг. Маленький запрос с большим лимитом даёт под, который отлично работает на пустой ноде и тормозит на загруженной, и это выглядит как плавающий баг.
Определяют доступный процессор через len(os.sched_getaffinity(0)). Привязка к ядрам отражает набор разрешённых ядер, а квоту не видит; свежая функция подсчёта ядер процесса тоже про привязку. Надёжных источников два: квота из cgroup и значение лимита, переданное в переменную окружения.