Различные методы отладки в OpenResty

API7.ai

December 16, 2022

OpenResty (NGINX + Lua)

В группе общения 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 недостаточно для инженеров по анализу ядра и производительности.

  1. Systemtap по умолчанию не входит в ядро системы.
  2. Он работает таким образом, что медленно запускается и может повлиять на нормальную работу системы.

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 — это наложение данных, взятых каждый раз, поэтому пользовательские данные — это ширина и длина блоков.

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

Заключение

Важно знать, что даже такая неинвазивная техника, как динамическая трассировка, не идеальна. Она может обнаружить только определенный отдельный процесс; в общем, мы включаем ее только на короткое время, чтобы использовать данные, взятые в этот период. Поэтому, если вам нужно обнаруживать через несколько сервисов или в течение длительного времени, вам все еще нужна распределенная техника трассировки, такая как opentracing.

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