Накладные расходы трассировки и безопасные альтернативы

Рейтинг: 78.5% · 14 голосов
Подробный курс по диагностике и производительности Linux для админов и DevOps: с чего начать, методология USE, логи (journalctl, dmesg), процессы, CPU, память и OOM, диск и IO (iostat), сеть (ss, tcpdump), системные вызовы и strace, ltrace, perf, флеймграфы, ftrace, eBPF и bpftrace, lsof, мониторинг. Разбор каждого инструмента с чтением вывода.
Ответить
Аватара пользователя
Dmitry_SRE
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Накладные расходы трассировки и безопасные альтернативы

Сообщение Dmitry_SRE »

Оглавление курса (47)
  1. С чего начать диагностику Linux: методология вместо паники
  2. Первые 60 секунд: экспресс-диагностика нагруженного сервера
  3. Методологии диагностики: USE, RED и здравый смысл
  4. Логи systemd через journalctl: где искать причину
  5. Где лежат логи Linux: /var/log, dmesg и rsyslog
  6. Источники правды: load average, /proc и /sys
  7. Процессы Linux: ps, pstree и состояния процессов
  8. Интерактивный мониторинг: top и htop
  9. Метрики процессов во времени: pidstat
  10. Приоритеты и ограничения: nice, ionice, cgroups
  11. Сигналы и зависшие процессы: kill, и что делать с D-state
  12. Загрузка CPU: user, system, iowait, steal и контекст-свитчи
  13. Диагностика CPU по ядрам: vmstat и mpstat
  14. Профилирование CPU: perf top и поиск пожирателя
  15. Частоты, троттлинг и NUMA: turbostat и numastat
  16. Память Linux: RSS, VSZ, page cache и миф о нехватке памяти
  17. Сколько памяти занято: free, /proc/meminfo и vmstat
  18. Поиск утечек и пожирателей памяти: smem, pmap, smaps
  19. Swap и подкачка: swapon, swappiness, когда своп - это боль
  20. OOM killer: кто и за что убил процесс
  21. Память ядра и slab: slabtop и куда уходит RAM
  22. Подсистема ввода-вывода: путь запроса от приложения до диска
  23. Диагностика диска: iostat и чтение await, %util
  24. Кто грузит диск: iotop и атрибуция io процессам
  25. Файловые системы: df, du, иноды и куда делось место
  26. Глубокая диагностика блочного слоя: blktrace и biolatency
  27. Кеш страниц и грязные данные: dirty pages, fsync, drop_caches
  28. Сетевой стек Linux: путь пакета и где возникают задержки
  29. Сокеты и соединения: ss и netstat
  30. Захват трафика: tcpdump для диагностики сети
  31. Задержки и потери в сети: ping, mtr, диагностика латентности
  32. Сеть как источник проблем: nftables, conntrack, дропы
  33. Что такое системный вызов и зачем его трассировать
  34. strace: трассировка системных вызовов на практике
  35. strace в бою: почему программа висит, падает или тормозит
  36. ltrace: трассировка вызовов библиотек
  37. Накладные расходы трассировки и безопасные альтернативы (вы здесь)
  38. perf: универсальный профайлер Linux
  39. Флеймграфы: визуализация профиля производительности
  40. Трассировка ядра: ftrace и trace-cmd
  41. eBPF: революция в наблюдаемости Linux
  42. Инструменты eBPF на практике: BCC и bpftrace
  43. lsof: открытые файлы, дескрипторы, кто держит файл и порт
  44. Разбор кейса: приложение тормозит - пошаговая диагностика
  45. Непрерывный мониторинг: sar, node_exporter, Grafana, Zabbix
  46. Диагностика в контейнерах: cgroups, лимиты, Docker и Kubernetes
  47. Карта инструментов и сквозной разбор инцидента производительности
Представь картину. На проде у тебя крутится боевой сервис, latency подрос, и ты, вооружённый знаниями из прошлых уроков, бодро пишешь sudo strace -p 12345, чтобы посмотреть, что там за syscall'ы творятся. Через пару секунд телефон взрывается алертами: время ответа улетело в небеса, очереди забились, балансировщик начал выкидывать ноды из ротации. Ты ничего не "сломал" руками - ты просто прицепил strace. И этого хватило.

Этот урок - самый важный по части техники безопасности. Мы разберём, почему strace и производительность - вещи плохо совместимые, в чём именно состоит ptrace overhead, когда трассировку через ptrace применять можно, а когда категорически нет, и какие современные дешёвые инструменты ставить на их место. К 2026 году ответ на вопрос "чем трассировать прод" почти всегда один: tracepoints и eBPF, а не ptrace.

Почему strace тормозит: механика ptrace overhead

strace и ltrace построены на системном вызове ptrace(2) - том же, на котором работает отладчик gdb. Идея ptrace простая и грубая: трассировщик становится управляющим процессом для цели и получает право останавливать её на каждом интересующем событии. Остановка - это не "подсмотреть на лету", это реальный перевод процесса в состояние stopped до тех пор, пока strace не разрешит ехать дальше.

Что физически происходит на каждом syscall трассируемой программы:
  • программа подходит к границе входа в ядро - ядро останавливает её и будит strace (переключение контекста);
  • strace просыпается, через ptrace читает регистры и аргументы вызова, печатает строку - программа всё это время стоит;
  • программа доходит до выхода из syscall - её снова останавливают, снова будят strace, тот читает результат (значение возврата, errno);
  • только теперь программа едет дальше.
Итого: на каждый один системный вызов - две остановки (на входе и на выходе) и минимум четыре переключения контекста между ядром, strace и целью. Аналогия для новичка: представь, что на каждом шаге тебя за плечо хватает контролёр, заглядывает в блокнот, что-то записывает, и только потом отпускает. Один шаг - терпимо. Миллион шагов в секунду - ты не дойдёшь никуда. А любая сетевая или I/O-нагруженная служба (БД, nginx, прокси, брокер очередей) делает именно десятки и сотни тысяч syscall'ов в секунду.

Цифры не абстрактные. В классическом замере Брендана Грегга ("strace Wow Much Syscall", 2014) программа под обычным strace выполнялась примерно в 173 раза медленнее. perf trace на похожей задаче давал порядка 1.36x. Замедление в десятки и сотни раз - это норма для ptrace, а не аномалия. Поэтому strace на проде и производительность нагруженного сервиса - почти всегда взаимоисключающие вещи.

Важный нюанс про однопоточность strace: пока strace обрабатывает остановку и печатает строку, цель ждёт именно его. Чем больше syscall'ов и чем медленнее терминал, в который сыплется вывод, тем хуже. Перенаправление вывода в файл (-o trace.log) и отказ от декодирования аргументов помогают, но природу ptrace это не меняет.

Изображение

Когда strace на проде допустим, а когда нет

Не нужно впадать в панику и считать strace злом. Это отличный инструмент, у него просто есть чёткая зона применения.

Можно (осторожно):
  • короткоживущая утилита или скрипт, который и так отрабатывает за секунды - тут замедление в разы тебе безразлично;
  • процесс на стейдже или тестовом стенде, где нет живого трафика;
  • "зависший" процесс, который ничего не делает и висит в одном syscall (например, в futex или read) - его уже некуда тормозить, strace тут спасатель: покажет, на чём именно встали;
  • точечный короткий замер на проде с жёстким таймаутом (timeout 2 strace ...) - подцепился на секунду и сразу отцепился.
Нельзя:
  • горячий процесс под живой нагрузкой, где важна latency (БД, прокси, API под трафиком);
  • единственный экземпляр сервиса без резерва - если он встанет, встанет всё;
  • "посмотрю-ка я тут подольше" - чем дольше висит ptrace, тем больше боли и тем выше шанс выйти за SLA.
Если strace на горячем процессе всё-таки неизбежен, режь объём перехвата. Фильтр по нужным вызовам резко снижает шум и нагрузку:

Код: Выделить всё

sudo strace -e trace=openat,connect -p 12345
А с флагом --seccomp-bpf (доступен начиная со strace 5.3) ядро через seccomp-фильтр останавливает процесс только на интересующих тебя вызовах, а все прочие пропускает без участия strace. Это серьёзно снижает накладные расходы, когда тебе нужна горстка конкретных syscall'ов, а не всё подряд:

Код: Выделить всё

sudo strace --seccomp-bpf -e trace=connect,sendto -p 12345
Но даже так на проде сначала тянись к инструментам без ptrace. Главное правило: strace на проде - это как операция на открытом сердце. Иногда необходимо, но не ставь её первой в очередь и не держи дольше нужного.

Безопасные альтернативы: perf trace и bpftrace

Современная замена ptrace - инструменты на perf и eBPF. Принципиальная разница: они не останавливают процесс. Ядро само пишет события в кольцевой буфер через статические точки трассировки (tracepoints), а инструмент читает буфер асинхронно, в стороне. Контролёр не хватает тебя за плечо - он просто ведёт журнал в углу, а ты идёшь своим ходом. На 2026 год это стандарт де-факто для прод-диагностики.

perf trace - почти как strace, но дёшево, потому что буферизует события в ядре, а не останавливает цель на каждом вызове.

Код: Выделить всё

sudo perf trace -p 12345
Вывод по структуре близок к strace:

Код: Выделить всё

     0.078 ( 0.011 ms): nginx/12345 epoll_wait(epfd: 9, events: 0x7ffd, maxevents: 512) = 1
     0.092 ( 0.005 ms): nginx/12345 recvfrom(fd: 14, ubuf: 0x55a, size: 16384) = 412
     0.101 ( 0.014 ms): nginx/12345 writev(fd: 14, vec: 0x7ffd, vlen: 2)          = 512
Как читать по полям, слева направо:
  • первое число - время от старта трассировки в миллисекундах (когда вызов произошёл);
  • в скобках - длительность самого syscall'а (сколько он выполнялся); подскочившие тут миллисекунды - первый кандидат на расследование;
  • comm/pid - имя процесса и PID (тут nginx/12345);
  • имя вызова и аргументы по именам полей;
  • после = - результат: число (для recvfrom это прочитанные байты, тут 412) или код ошибки вроде = -1 EAGAIN.
Длинная пауза в epoll_wait - это норма: процесс просто ждёт событий на сокетах, это не работа, а ожидание. А вот writev или fsync на десятки миллисекунд на быстром NVMe - уже сигнал копать в сторону I/O или насыщения диска. Массовые = -1 EAGAIN на recvfrom тоже норма для неблокирующих сокетов, а вот = -1 ECONNREFUSED или ETIMEDOUT на connect - это уже сетевая проблема.

Если нужен не поток, а сводка - что вызывалось чаще и где осело время:

Код: Выделить всё

sudo perf trace -s -p 12345
Флаг -s (--summary) по Ctrl+C выдаст таблицу по потокам с колонками: syscall, calls (сколько раз), errors (сколько с ошибкой), total (суммарное время, мс), и min/avg/max плюс относительный stddev на вызов. Смотри на строки с большим total - там тратится время; на ненулевой errors - там что-то идёт не так; большой max при маленьком avg - редкие, но болезненные хвостовые задержки. Если хочешь и поток, и сводку в конце - используй -S (--with-summary).

bpftrace - однострочники поверх eBPF, ещё гибче и дешевле для агрегатов. eBPF позволяет твоей крошечной программе исполняться прямо в ядре в момент события и считать суммы и гистограммы на месте, не гоняя каждое событие в userspace. Это следующий большой блок курса, тут - первое знакомство.

Сосчитать syscall'ы по всей системе и понять, кто грузит ядро (аналог strace -c, но глобально и почти бесплатно):

Код: Выделить всё

sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
По Ctrl+C получишь карту @[имя_процесса]: число вызовов. Кто наверху - тот и долбит ядро чаще всех.

Снупер открытий файлов - что и какой процесс реально открывает:

Код: Выделить всё

sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args.filename)); }'
Здесь comm - имя процесса, str(args.filename) превращает указатель из аргумента вызова в строку-путь. Полезно, когда сервис лезет не туда или ищет конфиг по неправильному пути. Замечание про синтаксис на 2026: в свежих bpftrace (с версии 0.25) предпочтителен доступ через точку - args.filename, со встроенным разыменованием. Стрелочный вариант args->filename ещё работает, но это старый стиль из примеров до 2024 года; в новых материалах пиши через точку. Узнать имена доступных полей tracepoint можно так:

Код: Выделить всё

sudo bpftrace -lv 'tracepoint:syscalls:sys_enter_openat'
Если же тебе всё-таки нужен именно strace, но дёшево по нагрузке, используй режим подсчёта вместо потока:

Код: Выделить всё

sudo strace -c -f -p 12345
Флаг -c копит статистику внутри strace и печатает одну сводную таблицу в конце (% time, seconds, usecs/call, calls, errors, syscall), а не строку на каждый вызов; -f добавляет дочерние потоки. Печать на экран - заметная часть тормозов strace, и -c её убирает. Но саму природу ptrace это не отменяет: на горячем проде даже strace -c всё равно дороже, чем perf trace.

Типичные грабли и заблуждения
  • "strace -c безопасен на проде". Нет. Он дешевле обычного strace, потому что не печатает каждую строку, но под ним всё ещё ptrace со своими остановками на входе и выходе. На нагруженном сервисе сначала тянись к perf trace.
  • "Я же подцеплюсь на секундочку". Под высоким RPS даже секунда ptrace - это десятки тысяч остановок и заметный провал по latency прямо в графиках мониторинга. Алерт прилетит быстрее, чем ты дочитаешь вывод.
  • Путать вывод. В perf trace число в скобках - длительность вызова, а число после = - результат (байты или код ошибки). В обычном strace длительности нет вообще; чтобы её увидеть, нужен флаг -T (тогда время появится в скобках в конце строки), а -t/-tt добавляют абсолютные временные метки. Не ищи длительность там, где её не включил.
  • bpftrace требует root и достаточно свежего ядра. Базово он работает с 4.9+, но удобные и стабильные фичи - это 5.x; кольцевой BPF ring buffer (более экономный по памяти и сохраняющий порядок событий, в отличие от старого per-CPU perf buffer) доступен с ядра 5.8. На очень старых ядрах из коробки bpftrace может не завестись - там остаётся perf.
  • eBPF не панацея: программа в ядре проходит верификатор и обязана быть безопасной, поэтому произвольную логику туда не запихнёшь. Но для трассировки syscall'ов, опен/exec-снуперов и подсчёта - этого с запасом хватает, и к 2026 году eBPF реально вытеснил strace/ltrace из роли инструмента первой линии на проде.
  • На Astra Linux и RED OS perf и bpftrace ставятся отдельными пакетами (обычно linux-tools или linux-perf и bpftrace) и иногда требуют установленных kernel headers под текущее ядро. Проверь наличие заранее, на спокойную голову, а не в момент инцидента.
Мини-лаба: повтори руками прямо сейчас
Возьми любой живой процесс (например, PID своего systemd-journald, sshd или nginx) и почувствуй разницу на себе.
  • Запусти sudo strace -c -f -p PID на 3-5 секунд, нажми Ctrl+C, посмотри сводку: какой syscall лидирует по % time и есть ли ненулевой столбец errors.
  • Тот же процесс через sudo perf trace -s -p PID на те же секунды - сравни таблицы и удобство, обрати внимание на колонки max и stddev.
  • Запусти глобальный sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }' на 5 секунд - кто в системе делает больше всего syscall'ов.
  • Запусти снупер sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args.filename)); }' и в соседнем терминале выполни cat /etc/hostname - найди своё открытие в потоке.
Засеки субъективно: под обычным strace без -c интерактивный процесс начинает заметно подлагивать, под perf trace и bpftrace - почти нет. Это и есть та самая разница в накладных расходах, о которой весь урок.

Контрольные вопросы
  • Почему strace замедляет программу в разы и десятки раз - что физически происходит на каждом syscall (сколько остановок и почему)?
  • Чем perf trace и bpftrace принципиально дешевле strace по механике - что они используют вместо остановок ptrace?
  • В каких ситуациях strace на проде допустим, а когда категорически нет, и как урезать его нагрузку, если он всё же нужен?
  • Что в выводе perf trace означает число в скобках, а что - число после знака равно?
Что запомнить
strace и ltrace стоят на ptrace, который останавливает процесс на каждом системном вызове (на входе и на выходе) - отсюда замедление в десятки и сотни раз и реальная опасность для нагруженного прода. На проде правило одно: сначала дешёвые инструменты на tracepoints (perf trace, bpftrace, strace -c для короткой сводки), и только если без точного потока никак - ptrace точечно, ненадолго, с фильтром по вызовам или --seccomp-bpf, на резервированном экземпляре. perf trace - твоя ежедневная замена strace, а bpftrace - мостик в мир eBPF, который к 2026 году стал стандартом прод-трассировки и которым мы займёмся дальше.
👍5 ❤️3 🔥2 😄 🤔1
Аватара пользователя
darkstack
Сообщения: 1
Зарегистрирован: 29 май 2026, 05:56

Re: Накладные расходы трассировки и безопасные альтернативы

Сообщение darkstack »

Блин, я реально один раз положил так стейдж-базу: strace -p на мастере. Думал утилита легкая, читает и читает. Теперь понятно почему latency скакнула, спасибо что разжевали про две остановки на каждый вызов и про --seccomp-bpf, не знал что так можно резать перехват.
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
skynet8
Сообщения: 1
Зарегистрирован: 11 май 2026, 03:26

Re: Накладные расходы трассировки и безопасные альтернативы

Сообщение skynet8 »

А правильно понял: для быстрой проверки кто грузит ядро лучше сразу bpftrace с raw_syscalls и count, а strace -c уже когда нужен конкретный процесс? И perf trace на современном ядре всегда есть или его доставлять надо на Astra/RED OS?
👍 ❤️1 🔥 😄 🤔1
Ответить
← Предыдущая глава
ltrace: трассировка вызовов библиотек
Следующая глава →
perf: универсальный профайлер Linux

Все главы курса «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое системный вызов и зачем трассировать

Вернуться в «Диагностика и производительность Linux: логи, strace, perf и eBPF»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость