Python highload: CPU и memory troubleshooting
Python-сервис под нагрузкой потребляет много CPU или памяти. Как диагностировать и что можно делать, если проблема действительно в Python-коде?
Короткий ответ
Сначала отделяем CPU-bound, IO-bound, DB-bound и memory leak сценарии через метрики, traces и профилировщики. Затем выбираем действие: оптимизация алгоритма, batching, async/non-blocking IO, C-extension/NumPy, горизонтальное масштабирование или исправление leak-а.
Полный разбор
План начинается с наблюдаемости: latency, throughput, CPU, RSS, GC, allocation profile, event loop lag, connection pool, DB time и external dependency time. Без этого легко оптимизировать не тот слой: сервис может ждать базу, а не тратить CPU.
Если код CPU-bound, смотрим hot functions через cProfile/py-spy/scalene, асимптотику, лишние allocations, сериализацию, циклы на чистом Python. Возможные решения: изменить алгоритм, вынести тяжелую часть в NumPy/C-extension, batch-ить работу, использовать multiprocessing или отдельный worker. Если IO-bound, важны async/non-blocking clients, timeouts, pool sizing и backpressure.
Для памяти нужны tracemalloc/memory profiler/objgraph, анализ роста heap, кешей, ссылок, больших объектов и lifetime. Горизонтальное масштабирование полезно для stateless service, но оно не заменяет понимание bottleneck-а.
Теория
Python performance debugging начинается с классификации bottleneck-а. GIL важен, но далеко не каждая production-проблема вызвана GIL.
Типичные ошибки
- Сразу предлагать переписать сервис на Go.
- Не отличать CPU-bound от ожидания базы или сети.
- Лечить memory leak рестартами без поиска источника.
Как отвечать на собеседовании
- Назови cProfile/py-spy/scalene, tracemalloc и event loop lag.
- Отдельно проговори CPU-bound, IO-bound и DB-bound варианты.