Какие причины резкого роста CPU и памяти после деплоя кода на продакшн
Что проверяют
Есть ли у вас порядок действий при инциденте и знаете ли вы, где в Python-сервисе обычно прячется рост ресурсов. Первым делом хотят услышать про откат, и только потом про профилирование. Следом спрашивают, как отличить утечку от просто возросшего потребления.
Как отвечать
Сначала стабилизация: если рост на графиках совпадает по времени с релизом, откатываемся, а разбираемся на стенде. Затем гипотезы по группам:
- код: квадратичный алгоритм на реальном объёме данных, N+1 запросы в ORM (в Django это
select_relatedиprefetch_related), вся выборка в памяти вместо.iterator()или пачек, сериализация больших JSON; - кеши и глобальное состояние:
lru_cache(maxsize=None)или@cacheна функции с бесконечным набором аргументов, словарь на уровне модуля, который только растёт; - асинхронность: цикл без
await, который блокирует event loop и жжёт CPU, шторм ретраев к упавшему сервису, неограниченное число задач; - зависимости: обновилась библиотека, особенно с C-расширением, где утечку не видно из Python;
- конфигурация: больше воркеров gunicorn, убран
max_requests, включён уровень логированияDEBUG.
Инструменты: py-spy top и py-spy dump подключаются к живому процессу без перезапуска и показывают, где тратится CPU, py-spy record строит flame graph. Для памяти подойдут tracemalloc со сравнением двух снимков, memray и objgraph для поиска растущих типов объектов.
Утечку выдаёт форма графика: память растёт линейно и не падает. Ступенька вверх после деплоя и дальше плато говорят скорее о новом базовом уровне потребления.
Где спотыкаются
Начинают профилировать на проде, пока пользователи страдают, вместо того чтобы сначала откатиться.
Не знают, что CPython не всегда возвращает освобождённую память операционной системе: RSS после пика может остаться высоким, хотя объекты уже удалены. Это ещё не утечка.
Сразу винят код, не проверив, что поменялось в окружении: переменные, число воркеров, лимиты контейнера.