Различные методы отладки в OpenResty
API7.ai
December 16, 2022
В группе общения OpenResty разработчики часто задают такой вопрос: Как отлаживать в OpenResty? Насколько мне известно, в OpenResty есть некоторые инструменты, поддерживающие отладку с точками останова, включая плагин в VSCode, но они пока не получили широкого распространения. Включая автора agentzh и нескольких известных мне участников, все используют простейшие ngx.log и ngx.say для отладки.
Это недружелюбно для большинства новичков. Означает ли это, что многие основные разработчики OpenResty используют только примитивный метод вывода логов, когда сталкиваются с трудной проблемой?
Конечно, нет. В мире OpenResty SystemTap и flame graph являются стандартными инструментами для решения сложных проблем и вопросов производительности. Если у вас есть вопрос на эту тему в рассылке или issue, сопровождающий проекта попросит вас загрузить flame graph и запросит графическое, а не текстовое описание.
В следующих двух статьях я расскажу вам об отладке и наборе инструментов, созданных OpenResty специально для отладки. Сегодня мы начнем с рассмотрения того, что доступно для отладки программ.
Точки останова и вывод логов
Долгое время в своей работе я полагался на продвинутые функции отладки IDE (интегрированной среды разработки) для трассировки программ, что казалось естественным. Для проблем, которые можно воспроизвести в тестовой среде, независимо от их сложности, я уверен, что смогу добраться до корня проблемы. Причина в том, что ошибка может быть воспроизведена многократно, и ее причину можно найти, установив точки останова и выводя логи. Все, что нужно, — это терпение.
С этой точки зрения, решение стабильно повторяющихся ошибок в тестовой среде — это физическая работа. Большинство ошибок, которые я решаю в своей работе, относятся к этой категории.
Однако обратите внимание, что есть два предварительных условия: тестовая среда и стабильное воспроизведение. Реальность всегда менее идеальна. Если ошибка воспроизводится только в производственной среде, есть ли способ ее отладить?
Здесь я рекомендую инструмент — Mozilla RR. Вы можете использовать его как повторитель, записывать поведение программы, а затем многократно воспроизводить его. Честно говоря, независимо от производственной или тестовой среды, если вы можете записать "доказательство" ошибки, оно может быть использовано как "доказательство в суде" для медленного анализа.
Алгоритм бинарного поиска и комментарии
Однако для некоторых крупных проектов, например, ошибка может исходить от одного из нескольких сервисов, или может быть проблема с SQL-запросом к базе данных, в этом случае, даже если ошибка может быть стабильно воспроизведена, вы не можете быть уверены, в какой части произошла ошибка. Таким образом, инструменты записи, такие как Mozilla RR, не работают.
В этот момент вы можете вспомнить классический "алгоритм бинарного поиска". Сначала мы комментируем половину логики в коде, и если проблема сохраняется, ошибка находится в не закомментированной части кода, поэтому мы комментируем оставшуюся половину логики и продолжаем цикл. В течение нескольких раз проблема сужается до полностью управляемого размера.
Этот подход может звучать немного глупо, но он эффективен во многих сценариях. Конечно, с развитием технологий и увеличением сложности систем, мы рекомендуем использовать стандарт, такой как OpenTracing, для распределенной трассировки.
OpenTracing может быть встроен в различные части системы и сообщать о цепочке вызовов и отслеживании событий, состоящих из нескольких Span, на сервер через Trace ID для анализа и графического представления. Это может помочь разработчикам найти множество скрытых проблем, а исторические данные будут сохранены, чтобы мы могли сравнивать и просматривать их в любое время.
Кроме того, если ваша система более сложная, например, в среде микросервисов, то Zipkin, Apache SkyWalking — хорошие выборы.
Динамическая отладка
Методы отладки, которые я описал выше, достаточно для решения большинства проблем. Однако, если вы столкнетесь с ошибкой, которая происходит только изредка в производственной среде, потребуется довольно много времени для ее отслеживания путем добавления логов и отслеживания событий.
Несколько лет назад я отвечал за систему, которая исчерпывала ресурсы базы данных около 1:00 ночи каждый день и вызывала лавину всей системы. В то время мы проверяли запланированные задачи в коде днем, а ночью команда ждала воспроизведения ошибки в компании, а затем проверяла состояние работы подмодулей, когда ошибка воспроизводилась. Мы не нашли причину ошибки до третьей ночи.
Мой опыт похож на историю нескольких инженеров системы Solaris, которые создали Dtrace. В то время инженеры Solaris также проводили дни и ночи, устраняя странную производственную проблему, только чтобы обнаружить, что это произошло из-за неправильно написанной конфигурации. Но в отличие от меня, инженеры Solaris решили полностью избежать этой проблемы и изобрели Dtrace, специально для динамической отладки.
В отличие от статических инструментов отладки, таких как GDB, динамическая отладка может отлаживать онлайн-сервисы. Весь процесс отладки нечувствителен и неинвазивен для отлаживаемой программы, без изменения кода, не говоря уже о перезапуске. Чтобы использовать аналогию, динамическая отладка похожа на рентген, который может исследовать тело пациента без необходимости забора крови и гастроскопии.
Dtrace был одним из первых фреймворков динамической трассировки, и его влияние привело к появлению аналогичных инструментов динамической отладки на других системах. Например, инженеры Red Hat создали Systemtap на Linux, о котором я расскажу далее.
Systemtap
Systemtap имеет свой DSL, который можно использовать для установки точек зондирования. Прежде чем мы углубимся в детали, давайте установим Systemtap, чтобы выйти за пределы абстрактного. Здесь просто используйте пакетный менеджер системы для установки.
sudo apt install systemtap
Давайте посмотрим, как выглядит программа hello world, написанная на Systemtap:
# cat hello-world.stp probe begin { print("hello world!") exit() }
Не выглядит ли это легко? Вам нужно использовать привилегии sudo для запуска.
sudo stap hello-world.stp
Она выведет hello world!. В большинстве сценариев нам не нужно писать свои скрипты stap для анализа, потому что OpenResty уже имеет множество готовых скриптов stap для регулярного анализа, и я представлю их вам в следующей статье. Итак, сегодня нам нужно кратко понять скрипты stap.
После некоторой практики вернемся к нашей концепции, Systemtap работает, преобразуя вышеуказанный скрипт stap в C и запуская системный компилятор C для создания модуля kernel. Когда модуль загружается, он активирует все события зондирования, подключаясь к ядру.
Например, begin будет выполняться в начале зондирования, и соответствующий end, поэтому программа hello world выше может быть написана следующим образом:
probe begin { print("hello ") exit() } probe end { print("world!")
Здесь я дал лишь очень поверхностное введение в Systemtap. Фрэнк Ч. Эйглер, автор Systemtap, написал электронную книгу Systemtap tutorial, которая подробно представляет Systemtap. Если вы хотите узнать больше и глубоко понять Systemtap, я предлагаю начать с этой книги как лучшего пути обучения.
Другие фреймворки динамической трассировки
Systemtap недостаточно для инженеров по анализу ядра и производительности.
Systemtapпо умолчанию не входит в ядро системы.- Он работает таким образом, что медленно запускается и может повлиять на нормальную работу системы.
eBPF (расширенный BPF) — это новая функция, добавленная в ядро Linux в последние годы. По сравнению с Systemtap, eBPF имеет преимущества прямой поддержки ядра, отсутствия сбоев и быстрого запуска. В то же время он не использует DSL, а напрямую синтаксис C, поэтому начать намного проще.
Кроме открытых решений, VTune от Intel также является одним из лучших инструментов. Его интуитивно понятный интерфейс и представление данных позволяют анализировать узкие места производительности без написания кода.
Flame Graph
Наконец, давайте вспомним flame graph, упомянутый в предыдущей статье. Как мы упоминали ранее, данные, генерируемые такими инструментами, как perf и Systemtap, могут быть более наглядно представлены с помощью flame graph. На следующей диаграмме приведен пример flame graph.

В flame graph цвет и оттенок цветных блоков не имеют значения, просто для простого различия между разными цветными блоками. Flame graph — это наложение данных, взятых каждый раз, поэтому пользовательские данные — это ширина и длина блоков.
Для flame graph на CPU ширина цветного блока — это процент времени CPU, занимаемого функцией: чем шире блок, тем больше потери производительности. Если есть плоская вершина, это место узкого места производительности. Длина цветного блока, с другой стороны, представляет глубину вызова функции, с верхним блоком, показывающим выполняемую функцию, и всеми ниже — вызывающими этой функции. Таким образом, функция ниже является супертипом функции выше: чем выше пик, тем глубже вызов функции.
Заключение
Важно знать, что даже такая неинвазивная техника, как динамическая трассировка, не идеальна. Она может обнаружить только определенный отдельный процесс; в общем, мы включаем ее только на короткое время, чтобы использовать данные, взятые в этот период. Поэтому, если вам нужно обнаруживать через несколько сервисов или в течение длительного времени, вам все еще нужна распределенная техника трассировки, такая как opentracing.
Какие инструменты и техники отладки вы используете в своей регулярной работе? Пожалуйста, оставьте комментарий и обсудите со мной, также приветствуется, если вы поделитесь этой статьей с друзьями, чтобы мы могли учиться и прогрессировать вместе.