Глава 9: Инструменты BCC — Глубокая трассировка ядра
Обзор
Коллекторы Tier 1 читают счётчики из /proc — они говорят что происходит (CPU занят на 90%). Но они не могут сказать почему (какой процесс, какая функция, какое распределение задержек).
Здесь на сцену выходят инструменты BCC (BPF Compiler Collection). Они прикрепляют eBPF-программы к функциям ядра и трассируют события в реальном времени, предоставляя гистограммы, детали событий и стек-трейсы.
Пакет internal/executor/ управляет безопасным запуском этих инструментов и парсингом их вывода.
Файлы исходного кода: executor/
| Файл | Строк | Назначение |
|---|---|---|
executor.go |
133 | BCCExecutor — запуск внешних бинарников с проверками |
security.go |
133 | SecurityChecker — верификация целостности бинарников |
registry.go |
181 | Registry — каталог 20 инструментов BCC |
parsers.go |
463 | Парсеры вывода (гистограммы, таблицы, стеки) |
aggregate.go |
149 | Агрегация событий (top-N, соединения) |
Экзекьютор: Как запускаются BCC инструменты
BCCExecutor.Run()
func (e *BCCExecutor) Run(ctx context.Context, toolName string, duration time.Duration) (*model.Result, error) {
spec, ok := Registry[toolName] // Поиск спецификации
binary := e.security.ResolveBinary(spec.Binary) // Поиск и проверка пути
args := spec.BuildArgs(duration) // Сборка аргументов CLI
env := e.security.SanitizeEnv() // Очистка окружения
cmd := exec.CommandContext(ctx, binary, args...)
cmd.Env = env
cmd.Stdout = NewLimitedWriter(50 * 1024 * 1024) // Лимит вывода 50МБ
cmd.Start()
cmd.Wait() // Ожидание завершения или таймаута
result := spec.Parser(output) // Парсинг вывода
}
LimitedWriter — Защита вывода
Некоторые инструменты (например, execsnoop, tcpdrop) генерируют вывод на каждое событие. На нагруженном сервере это могут быть гигабайты. Лимит в 50МБ предотвращает исчерпание памяти.
Модель безопасности
Почему это важно
Инструменты BCC работают от root и могут трассировать ЛЮБУЮ функцию ядра. Скомпрометированные бинарники могут: - Читать произвольную память ядра - Модифицировать системные вызовы - Логировать чувствительные данные
SecurityChecker
- Разрешённые пути: Бинарники ищутся только в доверенных директориях (
/usr/share/bcc/tools,/usr/sbin,/usr/bin). - Верификация прав: Файл должен принадлежать
root(UID 0) и не быть доступным для записи всем (world-writable). - Очистка окружения: Удаляются переменные типа
LD_PRELOAD,LD_LIBRARY_PATH, чтобы предотвратить подмену библиотек.
Парсеры вывода
ParseHistogram() — Распределения
Вывод BCC гистограммы:
usecs : count distribution
4 -> 7 : 15 |**** |
8 -> 15 : 107 |***************************** |
16 -> 31 : 145 |****************************************|
Парсер преобразует это в структуру с перцентилями (P50, P90, P99). Перцентили вычисляются путём итерации по бакетам.
ParseFoldedStacks() — Flame Graph
Для профилирования вывод выглядит как "свернутые" стеки:
Это парсится в структуру StackTrace, из которой затем строится SVG Flame Graph.
Интерпретация результатов (Thresholds)
runqlat — Очередь CPU
| Перцентиль | Хорошо | Внимание | Критично |
|---|---|---|---|
| p50 | < 10μs | 10-100μs | > 100μs |
| p99 | < 100μs | 100-1000μs | > 1ms |
biolatency — Дисковые задержки
| Перцентиль | SSD | HDD | Критично |
|---|---|---|---|
| p50 | < 100μs | < 5ms | — |
| p99 | < 1ms | < 20ms | > 50ms |
tcpconnlat — Установка соединения
| Латентность | Значение |
|---|---|
| < 1ms | Тот же датацентр |
| 1-5ms | Тот же регион |
| > 100ms | Межконтинентальная сеть или перегрузка |
| > 1000ms | Проблемы с DNS или маршрутизацией |
Далее: Глава 10 — Нативный eBPF