Профилирование Go-приложений
Рассказываем, что такое профилирование и почему это крутой инструмент для оптимизации приложений.
Что такое профилирование?
Это штука, которая помогает понять, как программа использует ресурсы. Вы собираете статистику, анализируете и визуализируете её, а затем — улучшаете работу сервисов.
Когда вы профилируете приложения, вы узнаёте, какие его части жадно пожирают ресурсы. Вообще большое потребление — это не баг сам по себе. Но слишком интенсивный расход повышает стоимость использования сервиса. А отсутствие лимитов на процессор и память при работе в Kubernetes (или на хосте) неприятно сказывается на работе других сервисов.
Как профилировать?
Способов несколько. Например, в golang есть встроенный профилировщик pprof. С ним можно вручную вызывать сбор нужных метрик из пакета pprof. А можно использовать NiP-сервер из net/http/pprof, который создаёт соответствующие эндопоинты для сбора метрик снаружи сервиса. Проще и удобнее использовать http-сервер pprof, так как ручной сбор нужен в редких случаях.
Что нужно делать?
- Сначала создайте простенький веб-сервис со встроенным профилировщиком (можете вручную, если у вас мазохистические наклонности);
- Запустите этот веб-сервер и подайте на него небольшую нагрузку (только не переборщите, чтобы сервер не расплавился);
- Снимите профиль CPU — при желании добавьте параметр времени;
- Вуаля! Теперь посмотрите, на какие функции вы потратили больше всего времени.
Для удобства визуализируйте информацию профиля CPU на графике:
- Чем толще стрелка, тем больше времени данный узел или любой из нижележащих узлов находился в стек-трейсере во время профилирования;
— Проценты показывают, сколько времени составляет каждый узел от общего времени профилирования;
- Ширина графа отображает общее затраченное время на каждый семпл;
- Ручейки — это цепочки вызовов. Их длина не влияет на производительность, так что не беспокойтесь.
Важно: профилировщик работает не постоянно, а включается короткими семплами по 20 секунд.
Этапы профилирования памяти
Тут всё просто: сделайте бенчмарк,
запустите команду,
проанализируйте топ и визуализируйте информацию на графике.
Необходимо посмотреть дерево выводов с наибольшим потребление и оптимизировать его.
Этот способ подходит для локальных проверок и локальных тестов. Если вы обнаружите утечку памяти на живом проде, то лучше поискать другие методы. Например, «endpoint« или »test runner».
Кстати, есть классный инструмент, чтобы решать такие проблемы, — Pyroscope. Этот сервис следит за вашими программами, как дедуля-сторож на скамейке. Собирает статистику про профиль памяти и процессора, количество GO-рутин, аллоцированные объекты и память. А потом рисует отчёты, чтобы вы могли разобраться, сколько у вас запросов и когда у них самые большие пики.
Pyroscope — это платформа непрерывного профилирования (аналогична Proff). Удобна в использовании и дружит с Grafana. Подключать Pyroscope можно разными способами. Но самый простой — добавить строчку в деплой. Он автоматически схватит эту строчку и начнёт собирать данные.
У Pyroscope есть также профилировщики для других языков программирования. Можно поставить внешнего бинарного агента, который будет собирать данные и отправлять их на Pyroscope.
Есть плагин для Grafana, который анализирует количество запросов, обработанные заявки, потребление памяти и представляет информацию в виде красивых графиков.
Как нам помог Pyroscope?
Нам Pyroscope помог оптимизировать скорость работы сервиса массовых проверок ИНН. Мы обнаружили, где происходят блокировки и протечки памяти. С профилированием справились с этой головной болью в мгновение ока. В короткий срок закрыли задачу, теперь сервис работает как часы.