Этот урок - самый важный по части техники безопасности. Мы разберём, почему 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 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.
Код: Выделить всё
sudo strace -e trace=openat,connect -p 12345
Код: Выделить всё
sudo strace --seccomp-bpf -e trace=connect,sendto -p 12345
Безопасные альтернативы: perf trace и bpftrace
Современная замена ptrace - инструменты на perf и eBPF. Принципиальная разница: они не останавливают процесс. Ядро само пишет события в кольцевой буфер через статические точки трассировки (tracepoints), а инструмент читает буфер асинхронно, в стороне. Контролёр не хватает тебя за плечо - он просто ведёт журнал в углу, а ты идёшь своим ходом. На 2026 год это стандарт де-факто для прод-диагностики.
perf trace - почти как strace, но дёшево, потому что буферизует события в ядре, а не останавливает цель на каждом вызове.
Код: Выделить всё
sudo perf trace -p 12345
Код: Выделить всё
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.
Если нужен не поток, а сводка - что вызывалось чаще и где осело время:
Код: Выделить всё
sudo perf trace -s -p 12345
bpftrace - однострочники поверх eBPF, ещё гибче и дешевле для агрегатов. eBPF позволяет твоей крошечной программе исполняться прямо в ядре в момент события и считать суммы и гистограммы на месте, не гоняя каждое событие в userspace. Это следующий большой блок курса, тут - первое знакомство.
Сосчитать syscall'ы по всей системе и понять, кто грузит ядро (аналог strace -c, но глобально и почти бесплатно):
Код: Выделить всё
sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
Снупер открытий файлов - что и какой процесс реально открывает:
Код: Выделить всё
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args.filename)); }'
Код: Выделить всё
sudo bpftrace -lv 'tracepoint:syscalls:sys_enter_openat'
Код: Выделить всё
sudo strace -c -f -p 12345
Типичные грабли и заблуждения
- "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 замедляет программу в разы и десятки раз - что физически происходит на каждом 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 году стал стандартом прод-трассировки и которым мы займёмся дальше.