Диагностика

Введение

Экосистема Go предоставляет обширный набор API и инструментов для диагностики логических и производственных проблем в программах на Go. Эта страница кратко описывает доступные инструменты и помогает разработчикам выбрать подходящий инструмент для решения их конкретной задачи.

Решения для диагностики можно разделить на следующие группы:

Примечание: Некоторые инструменты диагностики могут мешать друг другу. Например, точное профилирование памяти искажает CPU профили, а профилирование блокировки горутин влияет на трассировку планировщика. Для получения более точной информации используйте инструменты по отдельности.

Профилирование

Профилирование полезно для выявления наиболее затратных или часто вызываемых участков кода. Среда выполнения Go предоставляет данные профилирования в формате, ожидаемом инструментом визуализации pprof. Данные профилирования можно собирать во время тестирования с помощью go test или через конечные точки, предоставляемые пакетом net/http/pprof. Пользователям необходимо собирать данные профилирования и использовать инструменты pprof для фильтрации и визуализации наиболее значимых путей выполнения кода.

Предопределённые профили, предоставляемые пакетом runtime/pprof:

Какие ещё профайлеры можно использовать для профилирования программ на Go?

В Linux можно использовать perf tools для профилирования программ на Go. Perf может профилировать и раскручивать cgo/SWIG код и ядро, поэтому он может быть полезен для получения информации о производительности на уровне нативного/ядра. В macOS, Instruments можно использовать для профилирования программ на Go.

Можно ли профилировать сервисы в продакшене?

Да. Безопасно профилировать программы в продакшене, но включение некоторых профилей (например, профиля CPU) добавляет издержки. Следует ожидать снижения производительности. Потенциальную нагрузку можно оценить, измерив накладные расходы профайлера до его включения в продакшен.

Можно периодически профилировать сервисы в продакшене. Особенно в системе с множеством реплик одного процесса, выбор случайной реплики периодически — безопасная опция. Выберите продакшен-процесс, профилируйте его в течение X секунд каждые Y секунд и сохраняйте результаты для визуализации и анализа; затем повторяйте периодически. Результаты можно вручную и/или автоматически просматривать, чтобы выявить проблемы. Сбор профилей может мешать друг другу, поэтому рекомендуется собирать только один профиль за раз.

Какие лучшие способы визуализации данных профилирования существуют?

Инструменты Go предоставляют текстовую, графическую и callgrind визуализацию данных профилей с использованием go tool pprof. Ознакомьтесь с Profiling Go programs чтобы увидеть их в действии.


Список самых затратных вызовов в текстовом виде.


Визуализация самых затратных вызовов в виде графа.

Представление в виде weblist отображает самые затратные части исходного кода построчно в HTML-странице. В следующем примере показано, что 530 мс затрачено на runtime.concatstrings, а стоимость каждой строки представлена в списке.


Визуализация самых затратных вызовов в виде weblist.

Еще один способ визуализации данных профилирования — это flame graph. Flame graphs позволяют перемещаться по конкретному пути наследования, поэтому можно увеличивать или уменьшать масштаб определенных участков кода. Upstream pprof поддерживает flame graphs.


Flame graphs обеспечивают визуализацию для выявления самых затратных путей в коде.

Ограничены ли я только встроенными профайлерами?

Помимо того, что предоставляется средой выполнения, пользователи Go могут создавать свои собственные профили с помощью pprof.Profile и использовать существующие инструменты для их анализа.

Можно ли обслуживать обработчики профайлера (/debug/pprof/...) по другому пути и порту?

Да. Пакет net/http/pprof по умолчанию регистрирует свои обработчики в стандартном mux, но вы также можете зарегистрировать их самостоятельно, используя экспортируемые из пакета обработчики.

Например, следующий пример будет обслуживать обработчик pprof.Profile на :7777 по пути /custom_debug_path/profile:

package main

import (
  "log"
  "net/http"
  "net/http/pprof"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/custom_debug_path/profile", pprof.Profile)
  log.Fatal(http.ListenAndServe(":7777", mux))
}

Трассировка

Трассировка — это способ инструментирования кода для анализа задержек на протяжении жизненного цикла цепочки вызовов. Go предоставляет пакет golang.org/x/net/trace как минимальную трассировочную подсистему для каждого узла Go и предоставляет простую библиотеку инструментирования с минимальной панелью управления. Go также предоставляет трассировщик выполнения для отслеживания событий среды выполнения в определённом интервале.

Трассировка позволяет нам:

В монолитных системах relatively легко собирать диагностические данные из составных частей программы. Все модули находятся в одном процессе и разделяют общие ресурсы для записи логов, ошибок и другой диагностической информации. Как только система выходит за рамки одного процесса и начинает становиться распределённой, становится труднее проследить вызов, начиная с фронтенд-веб-сервера, до всех его бэкендов, пока ответ не будет возвращён пользователю. Именно здесь играет важную роль распределённое трассирование для инструментирования и анализа рабочих систем.

Распределённое трассирование — это способ инструментирования кода для анализа задержек на всём протяжении жизненного цикла пользовательского запроса. Когда система распределена и когда традиционные инструменты профилирования и отладки не масштабируются, вы можете использовать инструменты распределённого трассирования для анализа производительности пользовательских запросов и RPC.

Распределённое трассирование позволяет нам:

Экосистема Go предоставляет различные библиотеки распределённого трассирования для разных систем трассировки и независимые от бэкенда.

Существует ли способ автоматически перехватывать каждый вызов функции и создавать трассировки?

Go не предоставляет способа автоматического перехвата каждого вызова функции и создания span-ов трассировки. Необходимо вручную инструментировать код для создания, завершения и аннотирования span-ов.

Как следует распространять заголовки трассировки в библиотеках Go?

Вы можете распространять идентификаторы трассировки и теги в context.Context. Пока ещё нет канонического ключа трассировки или общего представления заголовков трассировки в индустрии. Каждый поставщик трассировки отвечает за предоставление утилит распространения в своих Go-библиотеках.

Какие ещё низкоуровневые события из стандартной библиотеки или среды выполнения могут быть включены в трассировку?

Стандартная библиотека и среда выполнения пытаются предоставить дополнительные API для уведомления о низкоуровневых внутренних событиях. Например, httptrace.ClientTrace предоставляет API для отслеживания низкоуровневых событий в жизненном цикле исходящего запроса. Идёт работа по получению низкоуровневых событий из трассировщика выполнения среды выполнения и возможности определять и записывать пользовательские события.

Отладка

Отладка — это процесс выявления причин некорректной работы программы. Отладчики позволяют нам понять поток выполнения программы и её текущее состояние. Существует несколько стилей отладки; в данном разделе будет рассмотрен только способ подключения отладчика к программе и отладка с помощью core dump.

Пользователи Go в основном используют следующие отладчики:

Насколько хорошо отладчики работают с программами на Go?

Компилятор gc выполняет оптимизации, такие как встраивание функций и регистрализация переменных. Эти оптимизации иногда усложняют отладку с помощью отладчиков. Идет работа по улучшению качества информации DWARF, генерируемой для оптимизированных бинарных файлов. Пока эти улучшения не станут доступны, рекомендуется отключать оптимизации при сборке отлаживаемого кода. Следующая команда собирает пакет без оптимизаций компилятора:

$ go build -gcflags=all="-N -l"
В рамках усилий по улучшению, в Go 1.10 был введен новый флаг компилятора -dwarflocationlists. Этот флаг заставляет компилятор добавлять списки расположений, которые помогают отладчикам работать с оптимизированными бинарными файлами. Следующая команда собирает пакет с оптимизациями, но с добавлением списков расположений DWARF:

$ go build -gcflags="-dwarflocationlists=true"

Какой интерфейс пользователя рекомендуется для отладчиков?

Несмотря на то, что и delve, и gdb предоставляют CLI, большинство интеграций с редакторами и IDE предоставляют специфичные для отладки пользовательские интерфейсы.

Возможно ли выполнять postmortem-отладку с программами на Go?

Файл дампа ядра — это файл, содержащий дамп памяти выполняющегося процесса и его статус. Он в основном используется для postmortem-отладки программы и для понимания её состояния во время выполнения. Эти два случая делают отладку дампов ядра хорошим диагностическим инструментом для postmortem-анализа и анализа рабочих сервисов. Возможно получить файлы дампов ядра из программ на Go и использовать delve или gdb для отладки, см. страницу отладки дампов ядра для пошагового руководства.

Статистика и события среды выполнения

Среда выполнения предоставляет статистику и отчеты о внутренних событиях для пользователей, чтобы диагностировать проблемы производительности и использования на уровне среды выполнения.

Пользователи могут отслеживать эти показатели, чтобы лучше понять общее состояние и производительность программ на Go. Некоторые часто отслеживаемые показатели и состояния:

Трассировщик выполнения

Go поставляется с трассировщиком выполнения среды выполнения для записи широкого круга событий среды выполнения. Планировщик, системные вызовы, сборка мусора, размер кучи и другие события собираются средой выполнения и доступны для визуализации с помощью инструмента go tool trace. Трассировщик выполнения — это инструмент для выявления проблем с задержками и использованием ресурсов. Вы можете проанализировать, насколько эффективно используется ЦП, и когда сетевые операции или системные вызовы становятся причиной принудительной остановки горутин.

Трассировщик полезен для:

Однако он не является идеальным инструментом для выявления горячих точек, например, анализа причин чрезмерного использования памяти или процессора. Вместо этого рекомендуется сначала использовать инструменты профилирования.

Выше показано визуальное представление трассировки, предоставленное инструментом go tool trace. Видно, что выполнение началось корректно, а затем стало сериализованным. Это может указывать на конкуренцию за совместный ресурс, который создаёт узкое место.

См. go tool trace для сбора и анализа трассировок среды выполнения.

GODEBUG

Среда выполнения также выводит события и информацию, если переменная окружения GODEBUG установлена соответствующим образом.

Переменная окружения GODEBUG может быть использована для отключения использования расширений набора инструкций в стандартной библиотеке и среде выполнения.

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang