Операционные системы
Отладка и профилирование
Production система крашится раз в неделю без объяснений. Логи чистые. Метрики нормальные. Воспроизвести локально не удаётся. Это кошмар каждого инженера. Но у FAANG-компаний есть секретное оружие: strace, perf, eBPF, ASan. Эти инструменты находят баги, которые невидимы обычными методами. Они работают на production без остановки сервиса. Они показывают то, что скрыто от debugger. Освоение этих инструментов - возможность дебажить системы любой сложности.
- **Netflix обслуживает 200+ млн пользователей.** Любой performance regression = миллионы долларов потерь. Используют perf + flame graphs для поиска CPU bottleneck. Результат: находят что 25% CPU уходит на устаревший кодек, переходят на новый → экономят 10M/год на серверах.
- **Cloudflare отражает DDoS атаки 46 млн requests/sec.** Используют eBPF/XDP для фильтрации пакетов прямо в ядре. Скорость: 24 млн packets/sec на одном ядре - в 10x быстрее чем iptables. eBPF защищает половину интернета от атак.
- **Facebook запускает ASan на 1% production серверов (canary).** Ловят use-after-free и buffer overflow ДО широкого rollout. Один пойманный баг спас от potential RCE exploit, который мог скомпрометировать миллионы аккаунтов.
Цели урока
- strace для трассировки syscalls процесса в реальном времени
- perf: CPU profiling, flame graphs (Brendan Gregg), hardware counters
- eBPF (BCC, bpftrace): observability one-liners без kernel modules
- Valgrind для memory errors (медленный, ~50x slowdown)
- AddressSanitizer (ASan, ~2x slowdown), TSan, UBSan для production hardening
Strace и Ltrace: рентген системных вызовов
**Strace** - инструмент, показывающий ВСЕ системные вызовы (syscalls) программы в реальном времени. Это как рентген процесса: видишь каждое взаимодействие с ядром - открытие файлов, сетевые запросы, выделение памяти, сигналы.
Production кейс: почему сервис тормозит?
Сервис API начал отвечать за 2 секунды вместо 50мс. Логи ничего не показывают. Запускаешь `strace -p <PID>` на production и видишь: ``` open("/etc/hosts", O_RDONLY) = 3 read(3, "127.0.0.1 localhost\n...", 4096) = 180 close(3) = 0 ``` Повторяется 1000 раз в секунду! Оказалось, библиотека DNS резолвинга читала `/etc/hosts` при каждом запросе вместо кеширования. Одна строка strace - час дебага сэкономлен.
**Ltrace** - аналог strace, но показывает вызовы библиотечных функций (libc, libssl, etc), а не системные вызовы. Используй когда проблема не в ядре, а в userspace библиотеках.
**Разница strace vs ltrace:** - **strace** → системные вызовы (ядро): `open()`, `read()`, `socket()`, `fork()` - **ltrace** → библиотечные функции (userspace): `malloc()`, `strlen()`, `SSL_connect()` Пример цепочки: ``` program → fopen() [ltrace видит] → внутри вызывает open() [strace видит] → ядро открывает файл ```
Debugging: программа зависает на старте
Запускаешь `./myserver`, он виснет без вывода. GDB не помогает (нет символов). Используешь strace: ```bash strace ./myserver ... connect(3, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("192.168.1.100")}, 16) = -1 ETIMEDOUT (Connection timed out) ``` БАМ! Сервер пытается подключиться к MySQL по IP 192.168.1.100, который недоступен. Таймаут 30 секунд. Проблема найдена за 5 секунд.
**Когда использовать strace/ltrace:** 1. Программа зависает - ищем на чём застряла (ждёт сети? диска? lock?) 2. Медленная работа - профилируем syscalls, смотрим где время 3. "Permission denied" - strace покажет КАКОЙ файл недоступен 4. Утечки файловых дескрипторов - считаем `open()` vs `close()` 5. Проблемы с DNS/network - видим все `connect()`, `sendto()`, `recvfrom()`
Production сервис начал медленно отвечать. `top` показывает низкую загрузку CPU (5%), но latency выросла с 10мс до 1 секунда. Какой инструмент поможет найти проблему?
Perf: CPU профилирование и flame graphs
**Perf** - стандартный Linux профайлер, использующий аппаратные счётчики процессора (PMU - Performance Monitoring Unit). Показывает где именно программа тратит CPU циклы - вплоть до отдельных инструкций и cache misses.
Real-world: оптимизация в Dropbox
Инженеры Dropbox использовали perf для оптимизации Python кода. Профилировали production серверы: ```bash perf record -g -p $(pgrep python) sleep 60 perf script | flamegraph.pl > flame.svg ``` Flame graph показал: 40% CPU времени уходит на парсинг JSON. Заменили стандартный `json` модуль на `ujson` (C-библиотека) - скорость выросла в 2 раза. Одна оптимизация сэкономила тысячи серверов.
**Flame Graphs (графы пламени)** - визуализация профиля. Ось X - алфавитный порядок (не время!), ось Y - глубина стека, ширина - сколько времени функция занимала CPU.
**Perf events: не только CPU циклы** Perf может мониторить аппаратные события: - `perf stat ./myapp` - базовая статистика (инструкции, cache misses, branch mispredictions) - `perf record -e cache-misses` - профиль L1/L2/L3 cache промахов - `perf record -e page-faults` - где происходят page faults (память свапается) - `perf record -e context-switches` - частота переключения контекста Пример: ```bash perf stat ./myapp 10,523,456,789 instructions # 10 млрд инструкций 512,345,678 cycles # 512 млн циклов 0.54 IPC # Instructions Per Cycle (эффективность) 12,345,678 cache-misses # Много! → оптимизировать locality ```
Netflix: perf для поиска CPU bottleneck
Netflix обслуживает 200+ млн пользователей. Любая оптимизация = миллионы экономии. Используют perf на production: 1. `perf record -ag -F 99 sleep 60` - профиль всех серверов 2. Генерируют flame graph → находят что 25% CPU уходит на сжатие видео устаревшим кодеком 3. Переходят на новый кодек (SVT-AV1) → CPU использование упало на 20% 4. Сэкономили ~10M/год на серверах Все благодаря одному flame graph.
**Когда использовать perf:** 1. Программа медленная, но непонятно где bottleneck 2. Оптимизация: найти функции, съедающие больше всего CPU 3. Анализ cache efficiency (много cache misses?) 4. Проверка после оптимизации (стало быстрее?) 5. Production profiling - можно запускать на живых серверах (overhead ~1-5%)
После запуска perf сгенерирован flame graph. На верхнем уровне (leaf) виден широкий блок функции `hash_table_lookup()`. Что это означает?
eBPF: программирование ядра без kernel modules
**eBPF (extended Berkeley Packet Filter)** - революция в Linux мониторинге. Позволяет запускать безопасный код прямо в ядре, без компиляции kernel modules. Трейсишь что угодно: syscalls, функции ядра, network packets, filesystem операции - всё в реальном времени с минимальным overhead.
**Почему eBPF безопасен?** Код проходит верификатор перед загрузкой: нет бесконечных циклов, нет обращений к невалидной памяти, ограниченный стек. Если верификатор отклоняет - программа не загрузится. Это как JIT в V8/JVM, но для ядра.
Production кейс: необъяснимые задержки в Kubernetes
Кластер Kubernetes начал показывать random latency спайки (99th percentile 500мс → 5 секунд). Логи чистые, метрики нормальные. Запускаем bpftrace на node: ```bash # Трейсим scheduler задержки (сколько процесс ждал CPU) sudo bpftrace -e ' tracepoint:sched:sched_switch { @qtime[args->next_pid] = nsecs; } tracepoint:sched:sched_wakeup { $wait = nsecs - @qtime[args->pid]; if ($wait > 1000000) { // > 1ms printf("PID %d waited %d ms\n", args->pid, $wait/1000000); } }' ``` Выясняется: один Pod жрёт 100% CPU, вызывая scheduler thrashing для соседей. cgroup limits не работали из-за бага в kernel 4.14. Обновили kernel → проблема ушла.
**BCC (BPF Compiler Collection)** - набор готовых eBPF инструментов: - `execsnoop` - логирует все запуски процессов (exec) - `opensnoop` - все открытия файлов - `tcpconnect` - все TCP подключения - `biolatency` - histogram disk I/O latency - `funccount` - счётчик вызовов функции (kernel или userspace) - `trace` - универсальный трейсер (аналог SystemTap) Пример: ```bash # Смотрим кто подключается по сети sudo tcpconnect PID COMM SADDR DADDR DPORT 1234 chrome 127.0.0.1 1.2.3.4 443 5678 ssh 10.0.0.5 20.0.0.10 22 ```
Cloudflare: eBPF для защиты от DDoS
Cloudflare обрабатывает 46 млн HTTP requests/sec. Используют eBPF для фильтрации DDoS атак прямо в ядре: 1. eBPF программа на XDP (eXpress Data Path) проверяет пакеты ДО стека TCP/IP 2. Блокирует вредоносные пакеты на скорости 24 млн packets/sec на ОДНОМ ядре 3. Обычный iptables/netfilter: ~2 млн pps В 10+ раз быстрее! eBPF работает на уровне сетевого драйвера, минуя весь networking stack.
**Когда использовать eBPF:** 1. Production debugging без перезагрузки - инжектишь код в ядро на лету 2. Performance анализ: где задержки? где contention? какие syscalls? 3. Security monitoring: трейсить все exec, file access, network connections 4. Network performance: XDP для packet filtering/load balancing 5. Kernel development: дебаг новых фич без пересборки ядра
Чем eBPF принципиально отличается от традиционных kernel modules (loadable kernel modules)?
Memory debugging: Valgrind, ASan, leak detection
**Memory bugs** - самые коварные: use-after-free, double-free, buffer overflow, memory leaks. Проявляются непредсказуемо: программа может работать месяцы, потом внезапно крашнуться. Инструменты memory debugging находят баги ДО того как они попадут в production.
**Типы memory багов:** 1. **Memory leak** - выделил память, забыл освободить (`malloc` без `free`) 2. **Use-after-free** - используешь память после `free()` (данные могут быть перезаписаны) 3. **Double-free** - вызвал `free()` дважды на один адрес (corruption heap) 4. **Buffer overflow** - запись за границы массива (`arr[100]` когда размер 50) 5. **Uninitialized memory** - читаешь переменную до инициализации (случайный мусор) 6. **Stack overflow** - бесконечная рекурсия или огромный stack array
**Valgrind минусы:** замедляет программу в 10-50 раз. Не подходит для production. Но отлично для testing: запускаешь тесты под Valgrind → находишь все memory issues.
Production кейс: intermittent crash в Redis
Redis периодически крашился раз в неделю без паттерна. Core dump не помогал (corrupted heap). Собрали Redis с ASan: ```bash make SANITIZER=address ./redis-server --sanitizer ``` Через 2 дня ASan поймал: ``` heap-use-after-free in module API callback ``` Оказалось: сторонний Redis модуль держал указатель на строку, которую Redis уже освободил. Одна строка - миллионы пользователей спасены от крашей.
**Сравнение инструментов memory debugging:**
| Инструмент | Скорость | Что находит | Использование |
|---|---|---|---|
| **Valgrind** | 10-50x медленнее | Leaks, use-after-free, overflows, uninit reads | Development/Testing |
| **ASan** | 2x медленнее | Overflows, use-after-free, double-free | Development/Testing/Canary prod |
| **TSan** | 5-15x медленнее | Data races, deadlocks | Development/Testing |
| **MSan** | 3x медленнее | Uninitialized memory reads | Development |
| **eBPF (bcc memleak)** | <5% overhead | Memory leaks в production | Production |
На практике: ASan в CI/CD, eBPF на production для мониторинга.
Facebook: ASan на production canary
Facebook запускает 1% production серверов с включённым ASan (canary deployments). Overhead 2x приемлем для небольшой части флота. Результат: - Ловят use-after-free и overflows ДО широкого rollout - Один пойманный баг спас от потенциального security incident (RCE exploit через buffer overflow) - ASan стал частью deployment pipeline: canary → ASan clean → rollout 100%
Ключевые идеи
- **strace/ltrace - рентген процесса:** показывают каждый syscall и library call в реальном времени. Незаменимы для debugging: программа виснет? strace покажет на чём. Permission denied? strace покажет какой файл. Работают на production с низким overhead.
- **perf - CPU профилирование через hardware counters:** записывает где программа тратит циклы процессора. Flame graphs визуализируют hotspots. Netflix/Dropbox оптимизируют production используя perf - находят функции, съедающие CPU, и ускоряют их в разы.
- **eBPF - программирование ядра без риска:** безопасно инжектишь код в kernel для трейсинга syscalls, network, scheduler. Верификатор гарантирует что не крашнет систему. Cloudflare использует для DDoS защиты, Uber - для performance мониторинга.
- **ASan/Valgrind - memory debugging:** находят use-after-free, buffer overflow, leaks. ASan в 2x медленнее (подходит для canary prod), Valgrind в 10-50x (только dev/test). Facebook/Google запускают ASan на production canary - ловят critical bugs до широкого rollout.
Связанные темы
Debugging и профилирование связаны со всеми аспектами системного программирования:
- Системные вызовы (syscalls) — strace показывает каждый syscall - понимание как программа взаимодействует с ядром критично для debugging
- Управление памятью — ASan/Valgrind находят memory corruption - нужно понимать как работает heap, stack, virtual memory
- Scheduling и multithreading — perf показывает context switches и CPU time - помогает оптимизировать многопоточные программы
- Networking — eBPF/XDP используют для packet filtering и network debugging - понимание TCP/IP стека обязательно
Вопросы для размышления
- Production сервис с latency 10мс, но раз в минуту происходит спайк до 5 секунд. Логи не показывают ошибок. Какие инструменты (strace/perf/eBPF) использовать и в какой последовательности для диагностики?
- Программа на C++ медленно жрёт память (1GB за сутки), но Valgrind показывает "no leaks". Как такое возможно? (Подсказка: reachable vs lost memory) Какими инструментами искать проблему?
- Почему eBPF считается безопасным для production, а обычный kernel module - нет? Какие гарантии даёт eBPF верификатор и какие баги он не может предотвратить?