Самые коварные вопросы в диагностике редко касаются того, сколько работы делает система. Гораздо чаще они начинаются со слов о том, что запускает этот скрипт каждые полчаса или почему сервер стал подтормаживать на привычных запросах. Привычные инструменты вроде метрик показывают только объём нагрузки и не объясняют её состав, и в такие моменты полезен взгляд на сами системные вызовы: в реальном времени, без отладочной сборки приложения и без остановки службы. Именно на этом этапе силён bpftrace: язык запросов поверх eBPF настолько краток, что диагностика отдельного события занимает одну строку в терминале. Разберём структуру запроса, подсчёт системных вызовов, гистограммы задержек и привычки аккуратной работы на живых серверах.
Что собой представляет bpftrace и почему его любят администраторы
В основе bpftrace лежит язык высокого уровня над eBPF: вместо написания программы вы записываете выражение из проб, фильтров и действий, оно проверяется встроенным верификатором на безопасность и внедряется в ядро как обработчик события внутренней телеметрии. Сбор статистики происходит прямо в точках наблюдения: системных вызовах, событиях планировщика, обращениях к файлам и запусках новых процессов. Пользователь читает только результат и ничего не меняет в среде исполнения самой службы, а это выгодно отличает его от запуска дополнительных агентов.
По сравнению с прежними схемами вроде фоновых служб трассировки упрощение огромное: никакой подготовки окружения и никаких правок приложения. Запуск из пакета, зависимость от заголовков ядра сведена к минимуму, работа внутри пространства ядра не влияет на ход приложений. Полезная привычка состоит в диагностике, а не в подготовке, потому что наблюдение встроено в ядро и не требует специальной подготовки или регистрации.
Для большинства задач администратора ценность видна на второй минуте контакта: вопрос, который раньше требовал отдельного скрипта на десятки строк, сейчас записывается одной строкой и читается с первого взгляда. Такой подход становится стандартным способом диагностики на ядре и остаётся почти единственным программным расширением, которое реально делается из терминала за минуты.
Анатомия однострочника и трассировочные точки
У однострочника строгая структура: точка наблюдения описывает, где должен сработать вызов, условие отсекает лишние процессы, а действие объясняет, что делать с событием. Язык построен по принципам awk по духу, поэтому одни и те же формы повторяются во всех примитивах этой системы, и переучиваться между разделами не требуется. Отдельная полезная черта это единство между учебными и боевыми стадиями: один и тот же запрос испытывается на стенде с моделью нагрузки, а потом заходит на прод в течение пяти секунд, и ничто из формы не переписывается. Такое разделение практически отменяет отдельный этап "обкатки" скрипта, ведь отлаживать в bpftrace приходится саму мысль, а не средство её выражения. Типичная привычка вокруг этого основана на таком порядке: сначала простейший print по событию, потом условие, дальше карта, и уже в конце интервалная агрегация. Любой эксперимент за пределами этого порядка богаче первичной диагностической процедурой.
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s
", comm, str(args->filename)); }'
# то же самое с фильтром на конкретный процесс
bpftrace -e 'tracepoint:syscalls:sys_enter_openat /pid == 4815/ { printf("%s
", str(args->filename)); }'
Точки наблюдения вида tracepoint стабильны от версии к версии, потому что они относятся к установленным интерфейсам ядра и не меняются произвольно. Фильтр по конкретному процессу уходит в краткую форму, и дело остаётся за тем, чтобы уменьшить размер просматриваемого потока событий до понятной очереди. Другие поля события стандартно содержат встроенные переменные вроде имени программы, пользователя и отметок времени, поэтому никакой возни с подготовкой не требуется.
Подсчёт системных вызовов и разделение по процессам
Самая привычная форма работы это подсчёт: каждый новый вызов увеличивает счётчик в карте ядра, а пользователь читает не отдельные события, а итоговую сводку. Написание занимает одну строку, потому что язык уже знает встроенные функции count, sum, min, max и хранит результат в ассоциативной карте автоматически:
bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); } interval:s:5 { print(@); clear(@); }'
# вызовов по типу каждые пять секунд с очисткой карты между выводами
Другой такой же запрос по процессам отвечает на гораздо более практический вопрос, какая программа отъедает системные вызовы, и он стартует занимаемой картой с полной уверенностью:
bpftrace -e 'tracepoint:syscalls:sys_enter_read { @[comm] = count(); }'
Такая сводная таблица приносит понимание того, где происходит цикл вызовов. Выяснить, каким именно процессом забита очередь чтения и сколько тактов тут заложено, имеет смысл до начала любого профиля, и это всё происходит на штатной системе без специальных утилит или внешнего наблюдения. Все данные доступны в памяти ядра прямо во время обращения и не требуют специального устройства хранения результатов. На поле отладки это превращается в отдельный привычный процесс: пользователь сразу видит, где лежит вызов в пакете ядра, ответ на первый запрос, а не после часа подготовки инфраструктуры.
Гистограммы задержек и карты статистики
Дальше счётчиков ценнее задержки. Для них у bpftrace есть функции hist и lhist: вторая раскладывает значения по линейным интервалам, первая лучше подходит для величин, растущих логарифмически. Читается не просто среднее время задержки, а само распределение, и по форме хвоста сразу видно, действительно ли проблема возникает изредка или существует постоянно.
bpftrace -e 'tracepoint:block:block_rq_issue { @start[args->sector] = nsecs; } tracepoint:block:block_rq_complete /@start[args->sector]/ { @lats = lhist(nsecs - @start[args->sector], 0, 2000000, 200000); delete(@start, args->sector); }'
Ключ к такому приёму это совмещение двух точек: отметка времени при постановке запроса к устройству и вторая отметка при его завершении. Механика универсальная: начало записывается рядом, а на завершении разность попадает в гистограмму. Отдельная тема это перенастройкаширины интервалов: одно и то же распределение в различных популяциях выглядит по-разному в зависимости от ёмкости буфера и окна времени, и реалистичный интервал выбирается под рабочий ритм проблемы, ориентация на которую появится ещё до новых правок. Именно поэтому гистограммы полюбились тем, кто привык измерять медленную запись и чтение по секундам, а не по ощущениям: итог виден в строках распределения, а многие редактируемые параметры компилируются, не теряя связи с набором.
Записи, буфер и ротация наблюдений через интервалы
На живой машине долгое наблюдение имеет свою цену: накопленная переменная растёт в памяти, а дополнительные данные лишь перегружают понимание. Практичное правило здесь идентично трассировке функций ядра: окно наблюдения ограничивается, карта очищается после печати, и никакой запас истории в буфере ядра не держится, а лишь последние пять секунд.
К этому добавляется устоявшая привычка собирать результаты в файл через тот же вывод: карта печатается и очищается, а следующий цикл отслеживается уже в новом окне. Такая точка зрения даёт и порцию ответственности: очищая карту мы не допускаем беспорядочной org формы устаревших событий, которые иногда простоят в памяти дольше, чем нужно.
Привычки аккуратной работы на живых серверах
Безопасность таких сеансов на боевых серверах зависит от привычек, и они оформляются вот так:
- первый запуск всегда самый короткий: влияние на загрузку узла измеряется на минимальном окне, и только потом разворачивается повторное наблюдение;
- фильтры вводятся по одному, потому что так проще понять, что именно в них убирается как лишнее;
- для длительного наблюдения выбирается запись печатей в файл, а на чистую память с событиями в пространстве ядра лучше не полагаться, потому что буфер копит только то, что ещё не записано; Отдельная грань здесь сводится к наблюдению за дисциплиной файла: то, что пишется в лог, должно быть следствием самого интервала, а не дополнительным предметом внимания. На большинстве нагруженных узлов интервал пять секунд уже достаточно мелкий, чтобы ни один всплеск не остался незамеченным, и это меет тот плюс, что файлы размещаются в каталоге лога с привязкой к часу, откуда их легко посмотреть без инструментов.
- собранные сведения удаляются после анализа, и это защищает машину от дополнительной нагрузки на память.
Такие привычки выглядят простыми лишь до первого полночного инцидента: после него становится понятно, почему они сохраняются в типовых документах на многих площадках.
Границы однострочников и следующий шаг к скриптам
Естественное продолжение коротких команд это файлы: когда условий и точек становится больше, их переводят в файл через флаг чтения, и из одноразовых заметок рождаются писаные программы наблюдений, исполняемые этим же интерпретатором. Такой переход обозначает смену быстрой диагностики на повседневную телеметрию: карты событий из одной строки становятся регулярными наблюдениями, работающими на расписании. Соответствие остаётся предельным: для тех, кому хватает одиночного запроса, скрипты дают преемственность без потери краткости, и технология увенчивается ровно тем уровнем контроля, который требуется реальному продукту.
Здесь история про быструю диагностику подходит к логическому концу, и дальше начинается практика: регулярный набор фильтров и гистограмм превращает карты вызовов в объяснимый материал, задокументированным по расписанию. Складывается экосистема из классических заметок о запуске, в которых каждая команда обещает выполнение своего поручения не только без сбоев, но и с измеримой экономией времени труда администратора.
Если искать в этой статье одну практическую максиму, она простая: сначала формулируется вопрос на языке системных вызовов, потом он задаётся как однострочная команда bpftrace, а потом формат разворачивается в полноценную сводную статистику. Порядок items рабочий: от печати к фильтру, от счётчика к гистограмме, от разового окна наблюдения к повторяющейся команде. Такой путь не требует ни бюджета компилируемых программ, ни инфраструктуры, и вся тяжесть применения для обывательского ядра измеряется одной командой, а не разбором.
Последний на честности момент занимает историю в памяти: выявленные инциденты дети отложенных ответов проверяются уже зафиксированными шаблонами, и никакая новая машина не должна подключаться к продакшен-мониторингу, пока у неё не будет такой же привычки к ритуалу эксплуатации. Складывается экосистема из заметок на сервере, в которой работа bpftrace однострочников даёт шанс измерять даже редучие проблемы пропускного типа почти сразу после того, как они возникают. И в этом месте стоит честно сказать про обратную связь: та же строка, которая помогла найти проблему, помогает и проверить её решение. Повторный запуск после правки конфигурации показывает, изменилось ли распределение, ушли ли редкие хвосты и сколько процентов вызовов перестало попадать в медленный интервал. Такой замкнутый цикл из вопроса, измерения, правки и повторного измерения превращает диагностику из искусства в ремесло, где каждая гипотеза получает числовое подтверждение, а каждое исправление оставляет после себя след в журнале наблюдений. Именно поэтому однострочники bpftrace занимают в руководствах по диагностике место в первых главах: они учат думать событиями ядра, не требуя ничего, кроме терминала и номера процесса. А грамотно собранный набор таких строк заменяет собой целую полку справочников по аварийной диагностике. При этом каждая из них остаётся читаемой, переносимой между машинами и пригодной к запуску прямо из журнала инцидента.