Redis eviction policies: какую стратегию вытеснения выбрать и почему
Когда приложение в проде зависает или молча падает — первое, за что стоит взяться, это strace. Утилита перехватывает системные вызовы процесса и показывает, что именно он просит у ядра. Никакой перекомпиляции, никаких дебаг-символов — подключился к PID и смотришь.
Что такое strace и когда нужен
strace — трассировщик системных вызовов (syscalls) в Linux. Каждый раз, когда процесс обращается к ядру — открывает файл, читает сокет, выделяет память — strace это логирует. Незаменим когда:
- Приложение падает без внятных логов
- Сервис зависает и не отвечает на запросы
- Непонятно, какие файлы/сокеты процесс открывает
- Нужно понять, почему процесс тормозит на I/O
Главное преимущество — работает с любым бинарником без исходников.
Базовые флаги: -p, -e, -f, -t
Минимальный набор, который покрывает 90% задач:
# Подключиться к работающему процессу
strace -p 12345
# Трассировать только определённые syscalls
strace -e trace=open,read,write ./myapp
# Следить за дочерними процессами
strace -f -p 12345
# Временные метки + дочерние + сеть
strace -tf -e trace=network -p 12345
Дополнительные флаги:
-c— статистика по syscalls (summary)-o file.log— вывод в файл-s 1024— увеличить длину строк-T— время выполнения каждого вызова
Реальный кейс: приложение висит на I/O
Node.js-сервис в проде перестал отвечать. Логи пустые, CPU около нуля. Подключаемся:
PID=$(pgrep -f "node server.js")
strace -p $PID -e trace=read,write,futex -T 2>&1 | head -30
Видим в выводе:
futex(0x7f3a2c000900, FUTEX_WAIT_PRIVATE, 2, NULL) = 0 <4.999872>
read(23, "", 65536) = 0 <5.000034>
Процесс висит на read с дескриптором 23, таймаут ровно 5 секунд. Проверяем дескриптор:
ls -la /proc/$PID/fd/23
# socket:[1847523]
ss -tnp | grep $PID
# ESTAB 10.0.3.15:43210 10.0.5.80:5432
Это TCP-соединение к PostgreSQL. База не отвечает — оказалось, pg_locks заблокировал таблицу из-за незавершённой миграции. Убиваем транзакцию — сервис оживает. Диагностика заняла 3 минуты.
Фильтрация по syscall
Группы для -e trace=:
# Файловые операции
strace -e trace=file ./app
# Сетевые вызовы
strace -e trace=network ./app
# Исключить шумные вызовы
strace -e trace=!futex,clock_gettime,epoll_wait -p $PID
Совет: начните с strace -c — покажет топ syscalls по количеству и времени. Дальше фильтруйте по самым частым.
Альтернативы: ltrace, perf, bpftrace
- ltrace — трассирует вызовы библиотечных функций (libc). Полезен, когда проблема не в syscalls, а в логике библиотеки.
- perf trace — аналог strace с меньшим оверхедом. Подходит для нагруженных сервисов.
- bpftrace — скриптуемый трассировщик на eBPF. Сложные условия: «покажи все read() дольше 100мс».
# perf trace: низкий оверхед
perf trace -p $PID --duration 100
# bpftrace: медленные read()
bpftrace -e 'tracepoint:syscalls:sys_exit_read { if (args->ret > 0) { printf("%d\n", nsecs); } }'
Подводные камни
- Оверхед — strace замедляет процесс в 10-100 раз. На проде используйте кратковременно.
- Многопоточность — без
-fвидите только главный тред. - Права — нужен root или
CAP_SYS_PTRACE. В Docker:--cap-add=SYS_PTRACE. - Контейнеры — в Kubernetes используйте
kubectl debugс ephemeral-контейнером.
strace — швейцарский нож для отладки в Linux. Не требует подготовки, работает с любым бинарником и даёт ответы за минуты. Освойте -p, -f, -e, -T — и большинство «необъяснимых» багов перестанут быть загадкой.