TGViewer
Сергей Озеранский Сергей Озеранский @sergeiozeranskii · 2.35K subscribers
Post #53 7.68K
🧠 Как 3 вечера анализа и оптимизаций дали минус 1 CPU и +40% к скорости ответов API

👀 Всё началось с того, что я случайно (ну как случайно, проблема была всегда, просто я первый задался вопросом - "почему?") заметил, что один Python-сервис на staging потребляет до 2.5 CPU.
Для сравнения — весь namespace потребляет около 6 CPU. То есть один сервис ест почти половину ресурсов. И это при том, что это не какой-то нагруженные сервис, это синхронный API-сервис, да еще и без нагрузки, это же staging.

Стало интересно — а что там внутри вообще так жрёт?

📦 Запустил профайлинг CPU через Pyroscope и… понеслось.

UI у Pyroscope меня не устроил — флеймграфы красивые, но неудобные для глубокого анализа.
📥 Поэтому я выгрузил дамп как pprof файл и открыл его через go tool pprof.
Так мне удобнее, быстрее и информативнее.

📊 Профилирование показало несколько важных узких мест:

🧱 Проблема №1: конвертация данных из MySQL

Самое "жирное" место — conversion.py → MySQLConverter.row_to_python.
Это код, который конвертирует строки из БД в Python-объекты на каждый запрос.

Наиболее затратные конвертации:
- _DECIMAL_to_python
- _INT_to_python
- _JSON_to_python
- _DATETIME_to_python
- _STRING_to_python

✅ Решение:

📌 Использовал C extension у mysql-connector-python
Официальная документация: https://dev.mysql.com/doc/connector-python/en/connector-python-cext.html

📉 Результат:
- Минус 1 CPU
- До +40% ускорение некоторых endpoint’ов

🧠 Проблема №2: неэффективный Python-код

Пример: функция change_type, которая:
- делает кучу проверок в логике
- использует неэффективные структуры данных, например, list для поиска вместо set / dict
- обрабатывает сразу множество возможных вариантов логики, в зависимости от входных данных

✅ Решение:

📌 Переписал участок без изменения бизнес-логики:
- заменил структуры данных
- добавил ранние выходы
- убрал дублирующиеся проверки

📌 Cognitive complexity снизилась, временная сложность — тоже. Производительность выросла.

⚠️ Проблема №3: код, который не нужен, но работает

Профайлинг показал, что куча ресурсов уходит на код, который вообще не должен уже как год использоваться. Но код активно выполняется. WTF!?

🤷‍♂️ Функции вызываются, результат — пустой, но код исполняется. Причём часто и тяжело.

✅ Решение:

📌 Удалил мёртвый код, обновил импорты, подчистил зависимости.
📌 Поднял вопрос о полной деактивации этого кода и мы таки это сделали — ресурсы можно использовать лучше.

🐘 Проблема №4: Импорты. Много. Дорого.

Во время анализа я наткнулся на ещё одну тихую, но дорогую проблему — огромные ресурсы уходят на фазу импорта модулей в Python.

Конкретно — на _find_and_load, часть механизма импорта, который занимается поиском, загрузкой и инициализацией модулей.

📌 Почему это важно?
- Импорты выполняются на каждый старт сервиса.
- Чем жирнее и зависимее ваши модули, тем дольше и тяжелее проходит импорт.
- Это не всегда очевидно, но можно видеть в профайлинге: _find_and_load, _find_and_load_unlocked, _load_unlocked – вот это всё.

📊 У нас в сервисе модулей реально много.
Многое из них – просто "свалены в кучу", где-то грузятся тяжёлые зависимости. Да и сложная структура проекта вынуждает иметь большое количество импортов.
И, как итог, CPU тратится на то, что можно было бы стремиться избежать.

✅ Что с этим делать:
- Разделять модули по функциональности.
- Отложенные импорты (lazy import) – практика может применяться (но есть нюансы), если модуль нужен только в конкретной функции.
- Минимизировать зависимости и импорт только того, что действительно нужно.
- Следить за импортами в __init__.py — именно они могут тянуть за собой пол кодовой базы.

Следующий шаг: memory профайлинг. Pyroscope в нашей инфрастуктуре такое не умеет и нужно приседать, но надеюсь дойдут руки и до RAM.
  • 🔥 35
  • 👍 8
  • ❤ 4
  • 👏 2
More from @sergeiozeranskii
  1. Sep 25, 2026Контейнеры в одном инструменте, виртуалки — в другом, частное облако — вообще отдельная ис…
  2. Sep 24, 2026Еще немного про ускорения. На этот раз про тесты, а точнее про coverage (Python). Библиоте…
  3. Sep 24, 2026Обнаружил, что агенты Claude Code в разных сессиях умеют общаться между собой. У меня сейч…
  4. Sep 23, 2026Возьмем Python-сервис в Kubernetes. Как правило на старте контейнера может проявляться спа…
  5. Sep 23, 2026Сегодня случилось страшное. То, чего я никак не ожидал. За все годы на MacBook со мной так…
  6. Sep 17, 2026Я вот не понимаю, зачем люди идут в OSS и контрибьютят на отвали. Ценности в этом ноль для…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →