Трассировка и профайлинг в Linux с помощью bcc/eBPF

18 октября 2017

Недавно у меня наконец-то дошли руки поиграться с eBPF. Если вдруг вы все пропустили, eBPF — это очередная реализация идеи «а давайте сделаем DTrace для Linux». Другой реализацией этой идеи является SystemTap. Только SystemTap трудно устанавливается, пользоваться им не очень удобно, и его страшно запускать на проде. В отличие от него, eBPF прямо-таки похож на нормальный инструмент. Давайте же поскорее с ним познакомимся!

Немного матчасти

Итак, что такое eBPF, и что такое bcc?

Аббревиатура eBPF расшифровывается как Enhanced Berkeley Packet Filter. Название возникло по историческим причинам, поскольку проект зародился, как попытка портировать BPF (эта штука, умеющая, например, фильтровать пакеты для libpcap / tcpdump прямо в ядре) из FreeBSD под Linux. Сейчас eBPF, несмотря на название, умеет намного больше, чем фильтровать пакеты (потому он и Enhanced) и представляет собой механизм ядра, предоставляющий возможности трассировки и профайлинга как самого ядра, так и пользовательских приложений. Иногда eBPF называют просто BPF’ом, что создает некоторую путаницу.

Тулкит для создания программ, использующих возможности eBPF, называется bcc (иногда также пишут прописными буквами, BCC). Название расшифровывается, как BPF Compiler Collection. При написании кода с использованием bcc в качестве языка программирования используется смесь Python и C. Также в bcc входит большой набор готовых утилит для профайлинга программ и мониторинга системы. Бытует мнение, что эти готовые программки даже полезнее возможности писать свои собственные.

Установка bcc/eBPF

Для использования bcc/eBPF вам понадобится ядро Linux версии 4.1 или старше. Если быть точнее, лучше использовать версию не младше 4.9, иначе часть клевых возможностей eBPF будет вам недоступна. Согласно файлу INSTALL.md из репозитория bcc, ядро должно быть собрано со следующими флагами:

CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_HAVE_BPF_JIT=y
CONFIG_BPF_EVENTS=y

Проверить их наличие можно командой:

zcat /proc/config.gz | grep BPF

Лично я тестировал bcc/eBPF на двух системах — Arch Linux с ядром 4.13.3 и Ubuntu 16.04 с ядром 4.10.0. В обеих системах ядро по умолчанию имеет нужные нам флаги.

Установка в Ubuntu 16.04 происходит так. Создаем /etc/apt/sources.list.d/iovisor.list:

sudo sh -c 'echo "deb [trusted=yes] https://repo.iovisor.org/apt/'\
'xenial xenial-nightly main" > /etc/apt/sources.list.d/iovisor.list'

Затем говорим:

sudo apt-get update
sudo apt-get install bcc bcc-tools python-bcc

В Arch Linux установить bcc/eBPF можно так:

yaourt -S bcc-git bcc-tools-git python-bcc-git

Про установку пакетов из AUR в этой операционной системе, а также про утилиту yaourt, ранее рассказывалось в заметке Управление пакетами в Arch Linux с помощью ABS и pacman.

Некоторые утилиты из bcc-tools

Скрипты из пакета bcc-tools лежат в каталоге /usr/share/bcc/tools/. Рассмотрим некоторые из них.

Для отображения запускаемых программ и их аргументов есть утилита execsnoop. Ее вывод выглядит как-то так:

PCOMM            PID    PPID   RET ARGS
sshd             7871   813      0 /usr/sbin/sshd -D -R
sh               7873   7871     0
uname            7878   7875     0 /bin/uname -m
cut              7885   7883     0 /usr/bin/cut -d  -f4
lsb_release      7884   7883     0 /usr/bin/lsb_release -sd
...

Если хочется узнать, какие процессы какие файлы открывают, воспользуйтесь opensnoop:

PID    COMM               FD ERR PATH
3450   i3status            4   0 /etc/mtab
3450   i3status            4   0 /proc/loadavg
754    psql                3   0 /usr/lib/locale/locale-archive
754    psql                3   0 /usr/share/locale/locale.alias
...

Посмотреть топ процессов по создаваемому ими дисковому I/O позволяет утилита biotop:

PID    COMM             D MAJ MIN DISK       I/O  Kbytes  AVGms
3388   dmcrypt_write    W 7   0   loop0      281  3524.0   0.66
3360   loop0            W 8   0   sda         76  3524.0   0.19
378    jbd2/sda2-8      W 8   0   sda        113   676.0   0.05
3360   loop0            R 8   0   sda         10    40.0   0.14
...

С помощью tcplife можно в реальном времени посмотреть, кто сожрал весь сетевой трафик:

PID  COMM   LADDR      LPORT RADDR           RPORT TX_KB RX_KB MS
3506 Chrome 10.128.0.6 33110 87.250.247.182  443       1    18 69347.77
3506 Chrome 10.128.0.6 37576 213.180.204.161 443       1    10 68529.41
3506 Chrome 10.128.0.6 37568 213.180.204.161 443       1    10 68529.48
3506 Chrome 10.128.0.6 42526 95.101.241.61   443       0     3 22147.14
3506 Chrome 10.128.0.6 42522 95.101.241.61   443       0     3 22147.23
3506 Chrome 10.128.0.6 56444 178.154.131.216 443       2    11 82244.22
3506 Chrome 10.128.0.6 56460 178.154.131.216 443       2     8 82157.24
3506 Chrome 10.128.0.6 56442 178.154.131.216 443       3   329 82290.86
...

Аналогичная утилита, но показывающая не лог реального времени, а топ процессов, называется tcptop:

PID    COMM    LADDR                 RADDR              RX_KB  TX_KB
18023  openvpn 192.168.27.173:59342  46.101.213.42:443     14     17
3534   Chrome  10.128.0.6:38314      104.244.42.1:443       5     10
3534   Chrome  10.128.0.6:35538      192.229.233.50:443     5      0
3534   Chrome  10.128.0.6:38336      104.244.42.1:443       5      5
...

Еще из особо интересных утилит я бы лично отметил cpudist, runqlat, filetop, biolatency, gethostlatency, а также совершенно выносящие мозг trace и argdist.

Всего на момент написания этих строк в bcc-tools входило около 100 утилит. Само собой разумеется, рассмотреть их все в рамках одного поста не представляется возможным. К счастью, описание каждой из утилит и поддерживаемых ею флагов можно прочитать, запустив утилиту с флагом -h. Кроме того, в подкаталоге /doc/ вы найдете примеры использования каждой из утилит.

Строим флеймграфы!

Какая же заметка про DTrace или его аналог может обойтись без флеймграфов? В случае с eBPF флеймграф для процесса с заданным pid строится как-то так:

sudo /usr/share/bcc/tools/profile -df -p 32133 > out.profile
git clone https://github.com/brendangregg/FlameGraph
./FlameGraph/flamegraph.pl --colors hot < out.profile > out.svg

Примерный вид результата:

Флеймграф, построенный с помощью bcc/eBPF

Здесь я профилировал PostgreSQL, выполняющий VACUUM FULL.

Иногда нужно замерить время, которое процесс проводит «off-cpu», к примеру, в sleep или ожидая ввода-вывода. В этом случае вам могут помочь утилиты offcputime и offwaketime. Они имеют такие же флаги, что и утилита profile.

Заключение

Написание собственных утилит с помощью bcc, увы, выходит за рамки данной заметки. Соответствующий туториал вы найдете в репозитории bcc. Кроме того, учиться можно по коду утилит из пакета bcc-tools.

Ссылки по теме:

Мои личные впечатления от bcc/eBPF исключительно положительные. Просто установил и пользуешься, ни о чем особо думать не нужно, и при этом не страшно запускать в продакшене. Правда, у меня возникли кое-какие проблемы с утилитой ext4slower. Кроме того, оказалось, что некоторые утилиты (например, dbstat и dbslower) требуют установки dtrace4linux для сборки профилируемых приложений с поддержкой USDT, что несколько неудобно. Но учитывая относительную молодость технологии, некоторые шероховатости были вполне ожидаемы. Я довольно уверен, что названные проблемы со временем поправят.

Дополнение: Основы трассировки с помощью bpftrace

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.