Spec-Zone.ru › nginx

Отладка nginx с помощью поставщика pid DTrace

Эта статья предполагает, что читатель обладает общими знаниями о внутреннем устройстве nginx и DTrace.

Хотя nginx, построенный с опцией --with-debug, уже предоставляет много информации о обработке запросов, иногда желательно более подробно проследить определенные части пути кода, одновременно исключив остальной вывод отладки. Поставщик pid DTrace (доступный в Solaris и macOS) — полезный инструмент для изучения внутреннего устройства программ пользовательского уровня, поскольку он не требует внесения каких-либо изменений в код и может помочь в этой задаче. Простой скрипт DTrace для отслеживания и печати вызовов функций nginx может выглядеть так:

#pragma D option flowindent

pid$target:nginx::entry {
}

pid$target:nginx::return {
}

Однако возможности DTrace для отслеживания вызовов функций предоставляют ограниченный объем полезной информации. Обычно более интересным, но и немного более сложным, является инспекция аргументов функций в реальном времени. Приведенные ниже примеры предназначены для того, чтобы помочь читателю лучше ознакомиться с DTrace и процессом анализа поведения nginx с помощью DTrace.

Один из распространенных сценариев использования DTrace с nginx заключается в следующем: подключение к процессу-рабочему nginx для протоколирования строк запросов и времени начала запросов. Соответствующая функция для подключения — ngx_http_process_request(), а аргумент — указатель на структуру ngx_http_request_t. Скрипт DTrace для такого протоколирования запросов может быть таким же простым, как:

pid$target::*ngx_http_process_request:entry
{
    this->request = (ngx_http_request_t *)copyin(arg0, sizeof(ngx_http_request_t));
    this->request_line = stringof(copyin((uintptr_t)this->request->request_line.data,
                                         this->request->request_line.len));
    printf("request line = %s\n", this->request_line);
    printf("request start sec = %d\n", this->request->start_sec);
}

Следует отметить, что в приведенном выше примере DTrace требует определенных знаний о структуре ngx_http_request_t. К сожалению, хотя можно использовать специфическую директиву #include в скрипте DTrace, а затем передать его препроцессору C (с флагом -C), это не работает должным образом. Из-за множества взаимных зависимостей почти все заголовочные файлы nginx необходимо включать. В свою очередь, в зависимости от настроек скрипта configure nginx-заголовки будут включать PCRE, OpenSSL и различные системные заголовочные файлы. Хотя теоретически все эти заголовочные файлы, относящиеся к конкретной сборке nginx, могут быть включены в предварительную обработку и компиляцию скрипта DTrace, на практике скрипт DTrace, скорее всего, не будет компилироваться из-за неизвестного синтаксиса в некоторых заголовочных файлах.

Вышеуказанную проблему можно решить, включив в скрипт DTrace только необходимые определения структур и типов. DTrace должен знать размеры структур, типы и смещения полей. Таким образом, зависимости можно далее уменьшить, вручную оптимизируя определения структур для использования с DTrace.

Давайте воспользуемся приведенным выше примером скрипта DTrace и посмотрим, какие определения структур ему нужны для корректной работы.

В первую очередь необходимо включить файл objs/ngx_auto_config.h, сгенерированный утилитой configure, поскольку он определяет ряд констант, влияющих на различные #ifdef. После этого в начале скрипта DTrace должны быть размещены некоторые базовые типы и определения, такие как ngx_str_t, ngx_table_elt_t, ngx_uint_t и т. д. Эти определения компактны, часто используются и вряд ли часто изменяются.

Затем идёт структура ngx_http_request_t, которая содержит множество указателей на другие структуры. Поскольку эти указатели действительно не относятся к данному скрипту и имеют одинаковый размер, их можно заменить указателями на void. Однако лучше добавить соответствующие типы вместо изменения определений:

typedef ngx_http_upstream_t     void;
typedef ngx_http_request_body_t void;

Наконец, необходимо добавить определения двух структур-членов (ngx_http_headers_in_t, ngx_http_headers_out_t), объявления функций обратного вызова и определения констант.

Финальный скрипт DTrace можно загрузить здесь.

Следующий пример демонстрирует вывод после запуска этого скрипта:

# dtrace -C -I ./objs -s trace_process_request.d -p 4848
dtrace: script 'trace_process_request.d' matched 1 probe
CPU     ID                    FUNCTION:NAME
  1      4 .XAbmO.ngx_http_process_request:entry request line = GET / HTTP/1.1
request start sec = 1349162898

  0      4 .XAbmO.ngx_http_process_request:entry request line = GET /en/docs/nginx_dtrace_pid_provider.html HTTP/1.1
request start sec = 1349162899

Используя аналогичные методы, читатель должен иметь возможность отслеживать другие вызовы функций nginx.

См. также

  • Руководство по динамическому прослеживанию Solaris
  • Вводная статья о поставщике pid DTrace

© 2002-2021 Igor Sysoev
© 2011-2024 Nginx, Inc.
Licensed under the BSD License.
https://nginx.org/en/docs/nginx_dtrace_pid_provider.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API