ΠžΡ‚ High Ceph Latency ΠΊ Kernel Patch с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ eBPF/BCC

ΠžΡ‚ High Ceph Latency ΠΊ Kernel Patch с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ eBPF/BCC

Π’ Linux Π΅ΡΡ‚ΡŒ большоС количСство инструмСнтов для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ ядра ΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ. Π‘ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ ΠΈΠ· Π½ΠΈΡ… Π½Π΅Π³Π°Ρ‚ΠΈΠ²Π½ΠΎ ΡΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ Π½Π° ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΈ Π½Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Ρ‹ Π² ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π΅.

ΠŸΠ°Ρ€Ρƒ Π»Π΅Ρ‚ Π½Π°Π·Π°Π΄ Π±Ρ‹Π» Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Π°Π½ Π΅Ρ‰Ρ‘ ΠΎΠ΄ΠΈΠ½ инструмСнт β€” eBPF. Он Π΄Π°Π΅Ρ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Ρ‚Ρ€Π°ΡΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ядро ΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ прилоТСния с Π½ΠΈΠ·ΠΊΠΈΠΌ ΠΎΠ²Π΅Ρ€Ρ…Π΅Π΄ΠΎΠΌ ΠΈ Π±Π΅Π· нСобходимости пСрСсборки ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌ ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ сторонних ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ Π² ядро.

БСйчас ΡƒΠΆΠ΅ сущСствуСт мноТСство ΠΏΡ€ΠΈΠΊΠ»Π°Π΄Π½Ρ‹Ρ… ΡƒΡ‚ΠΈΠ»ΠΈΡ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ eBPF, ΠΈ Π² этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ рассмотрим, ΠΊΠ°ΠΊ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΡΠΎΠ±ΡΡ‚Π²Π΅Π½Π½ΡƒΡŽ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ для профилирования Π½Π° основС Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ PythonBCC. Π‘Ρ‚Π°Ρ‚ΡŒΡ основана Π½Π° Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… событиях. ΠœΡ‹ ΠΏΡ€ΠΎΠΉΠ΄Π΅ΠΌ ΠΏΡƒΡ‚ΡŒ ΠΎΡ‚ появлСния ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ ΠΈ Π΄ΠΎ Π΅Ρ‘ исправлСния, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ, ΠΊΠ°ΠΊ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Ρ‹ ΡƒΠΆΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρ‹ Π² ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹Ρ… ситуациях.

Ceph Is Slow

Π’ кластСр Ceph Π΄ΠΎΠ±Π°Π²ΠΈΠ»ΠΈ Π½ΠΎΠ²Ρ‹ΠΉ хост. ПослС ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ части Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° Π½Π΅Π³ΠΎ ΠΌΡ‹ Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ запросов Π½Π° запись ΠΈΠΌ Π³ΠΎΡ€Π°Π·Π΄ΠΎ Π½ΠΈΠΆΠ΅, Ρ‡Π΅ΠΌ Π½Π° Π΄Ρ€ΡƒΠ³ΠΈΡ… сСрвСрах.

ΠžΡ‚ High Ceph Latency ΠΊ Kernel Patch с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ eBPF/BCC
Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Π΄Ρ€ΡƒΠ³ΠΈΡ… ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌ, Π½Π° этом хостС использовался bcache ΠΈ Π½ΠΎΠ²ΠΎΠ΅ ядро linux 4.15. Π₯ост Ρ‚Π°ΠΊΠΎΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ использовался здСсь Π²ΠΏΠ΅Ρ€Π²Ρ‹Π΅. И Π½Π° Ρ‚ΠΎΡ‚ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π±Ρ‹Π»ΠΎ ясно, Ρ‡Ρ‚ΠΎ ΠΊΠΎΡ€Π½Π΅ΠΌ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ тСорСтичСски ΠΌΠΎΠ³Π»ΠΎ Π±Ρ‹Ρ‚ΡŒ Ρ‡Ρ‚ΠΎ ΡƒΠ³ΠΎΠ΄Π½ΠΎ.

Investigating the Host

НачнСм с Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ посмотрим, Ρ‡Ρ‚ΠΎ происходит Π²Π½ΡƒΡ‚Ρ€ΠΈ процСсса ceph-osd. Для этого Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ perf ΠΈ flamescope (ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ ΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ здСсь):

ΠžΡ‚ High Ceph Latency ΠΊ Kernel Patch с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ eBPF/BCC
ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π³ΠΎΠ²ΠΎΡ€ΠΈΡ‚ Π½Π°ΠΌ ΠΎ Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ функция fdatasync() ΠΏΠΎΡ‚Ρ€Π°Ρ‚ΠΈΠ»Π° ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΏΡ€ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ΅ запроса Π² Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ generic_make_request(). Π—Π½Π°Ρ‡ΠΈΡ‚, Ρ‡Ρ‚ΠΎ скорСС всСго, ΠΏΡ€ΠΈΡ‡ΠΈΠ½Π° ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Π³Π΄Π΅-Ρ‚ΠΎ Π²Π½Π΅ самого Π΄Π΅ΠΌΠΎΠ½Π° osd. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π»ΠΈΠ±ΠΎ ядро, Π»ΠΈΠ±ΠΎ диски. Π’Ρ‹Π²ΠΎΠ΄ iostat ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π» Π²Ρ‹ΡΠΎΠΊΡƒΡŽ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ запросов bcache-дисками.

ΠŸΡ€ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ΅ хоста ΠΌΡ‹ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ Π΄Π΅ΠΌΠΎΠ½ systemd-udevd потрСбляСт большоС количСство Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ CPU β€” ΠΎΠΊΠΎΠ»ΠΎ 20% Π½Π° Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… ядрах. Π­Ρ‚ΠΎ странноС ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹ΡΡΠ½ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΏΡ€ΠΈΡ‡ΠΈΠ½Ρƒ. Π’Π°ΠΊ ΠΊΠ°ΠΊ Systemd-udevd Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с uevent’ами, ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Π½ΠΈΡ… Ρ‡Π΅Ρ€Π΅Π· udevadm monitor. ΠžΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ΡΡ, Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Π»ΠΎΡΡŒ большоС количСство change-событий для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π±Π»ΠΎΡ‡Π½ΠΎΠ³ΠΎ устройства Π² систСмС. Π­Ρ‚ΠΎ довольно Π½Π΅ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ, поэтому Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ всС эти ΠΈΠ²Π΅Π½Ρ‚Ρ‹.

Using the BCC Toolkit

Как ΠΌΡ‹ ΡƒΠΆΠ΅ выяснили, ядро (ΠΈ Π΄Π΅ΠΌΠΎΠ½ ceph Π² систСмном Π²Ρ‹Π·ΠΎΠ²Π΅) Ρ‚Ρ€Π°Ρ‚ΠΈΡ‚ ΠΌΠ½ΠΎΠ³ΠΎ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ Π² generic_make_request(). ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π·Π°ΠΌΠ΅Ρ€ΠΈΡ‚ΡŒ ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρ‹ этой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π’ BCC ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π·Π°ΠΌΠ΅Ρ‡Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° β€” funclatency. ΠœΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Ρ‚Ρ€Π°ΡΡΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π΅ΠΌΠΎΠ½ ΠΏΠΎ Π΅Π³ΠΎ PID с ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»ΠΎΠΌ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ‹Π²ΠΎΠ΄Π°ΠΌΠΈ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ Π² 1 сСкунду ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π² миллисСкундах.

ΠžΡ‚ High Ceph Latency ΠΊ Kernel Patch с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ eBPF/BCC
ΠžΠ±Ρ‹Ρ‡Π½ΠΎ эта функция Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ быстро. ВсС, Ρ‡Ρ‚ΠΎ ΠΎΠ½Π° Π΄Π΅Π»Π°Π΅Ρ‚ β€” ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚ запрос Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Π° устройства.

Bcache β€” это слоТноС устройство, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π½Π° самом Π΄Π΅Π»Π΅ состоит ΠΈΠ· Ρ‚Ρ€Π΅Ρ… дисков:

  • backing device (ΠΊΠ΅ΡˆΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ диск), Π² Π΄Π°Π½Π½ΠΎΠΌ случаС это ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹ΠΉ HDD;
  • caching device (ΠΊΠ΅ΡˆΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ диск), здСсь это ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·Π΄Π΅Π» NVMe устройства;
  • Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΉ дСвайс bcache, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

ΠœΡ‹ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° запроса Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΡ‚, Π½ΠΎ для ΠΊΠ°ΠΊΠΎΠ³ΠΎ ΠΈΠ· этих устройств? РазбСрСмся с этим Ρ‡ΡƒΡ‚ΡŒ ΠΏΠΎΠ·ΠΆΠ΅.

БСйчас ΠΌΡ‹ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ uevent’ы, вСроятно, приводят ΠΊ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°ΠΌ. Найти, Ρ‡Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΈΡ… Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΡŽ, Π½Π΅ Ρ‚Π°ΠΊ просто. ΠŸΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ это ΠΊΠ°ΠΊΠΎΠΉ-Ρ‚ΠΎ софт, запускаСмый пСриодичСски. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π·Π° софт запускаСтся Π² систСмС, с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ скрипта execsnoop ΠΈΠ· Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ Π½Π°Π±ΠΎΡ€Π° ΡƒΡ‚ΠΈΠ»ΠΈΡ‚ BCC. Запустим Π΅Π³ΠΎ ΠΈ Π½Π°ΠΏΡ€Π°Π²ΠΈΠΌ Π²Ρ‹Π²ΠΎΠ΄ Π² Ρ„Π°ΠΉΠ».

НапримСр Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

/usr/share/bcc/tools/execsnoop  | tee ./execdump

НС Π±ΡƒΠ΄Π΅ΠΌ здСсь ΠΏΡ€ΠΈΠ²ΠΎΠ΄ΠΈΡ‚ΡŒ ΠΏΠΎΠ»Π½Ρ‹ΠΉ Π²Ρ‹Π²ΠΎΠ΄ execsnoop, Π½ΠΎ ΠΎΠ΄Π½Π° ΠΈΠ½Ρ‚Π΅Ρ€Π΅ΡΡƒΡŽΡ‰Π°Ρ нас строка выглядСла Π²ΠΎΡ‚ Ρ‚Π°ΠΊ:

sh 1764905 5802 0 sudo arcconf getconfig 1 AD | grep Temperature | awk -F '[:/]' '{print $2}' | sed 's/^ ([0-9]*) C.*/1/'

Π’Ρ€Π΅Ρ‚ΡŒΡ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠ° это PPID (parent PID) процСсса. ΠŸΡ€ΠΎΡ†Π΅ΡΡΠΎΠΌ с PID 5802 оказался ΠΎΠ΄ΠΈΠ½ ΠΈΠ· ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² нашСй систСмы ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³Π°. ΠŸΡ€ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ систСмы ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³Π° Π±Ρ‹Π»ΠΈ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹ ΠΎΡˆΠΈΠ±ΠΎΡ‡Π½ΠΎ Π·Π°Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹. Π’Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Π° HBA-Π°Π΄Π°ΠΏΡ‚Π΅Ρ€Π° снималась Ρ€Π°Π· Π² 30 сСкунд, Ρ‡Ρ‚ΠΎ Π³ΠΎΡ€Π°Π·Π΄ΠΎ Ρ‡Π°Ρ‰Π΅, Ρ‡Π΅ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ. ПослС измСнСния ΠΈΠ½Ρ‚Π΅Ρ€Π²Π°Π»Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ Π½Π° Π±ΠΎΠ»Π΅Π΅ Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ, ΠΌΡ‹ ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠΈΠ»ΠΈ, Ρ‡Ρ‚ΠΎ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ запросов Π½Π° этом хостС пСрСстала выдСлятся Π½Π° Ρ„ΠΎΠ½Π΅ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… хостов.

Но всё Π΅Ρ‰Ρ‘ нСпонятно, ΠΏΠΎΡ‡Π΅ΠΌΡƒ bcache-устройство Ρ‚Π°ΠΊ Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΠ»ΠΎ. ΠœΡ‹ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΠ»ΠΈ Ρ‚Π΅ΡΡ‚ΠΎΠ²ΡƒΡŽ ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΡƒ с ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ‡Π½ΠΎΠΉ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠ΅ΠΉ ΠΈ ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Π»ΠΈ воспроизвСсти ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ, запустив fio Π½Π° bcache, пСриодичСски запуская udevadm trigger для Π³Π΅Π½Π΅Ρ€Π°Ρ†ΠΈΠΈ uevents.

Writing BCC-Based Tools

ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΏΡ€ΠΎΡΡ‚ΡƒΡŽ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ для трассировки ΠΈ Π²Ρ‹Π²ΠΎΠ΄Π° Π½Π° экран Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹Ρ… Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² generic_make_request(). Нас Ρ‚Π°ΠΊΠΆΠ΅ интСрСсуСт имя диска, для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π±Ρ‹Π»Π° Π²Ρ‹Π·Π²Π°Π½Π° эта функция.

План прост:

  • РСгистрируСм kprobe Π½Π° generic_make_request():
    • БохраняСм Π² ΠΏΠ°ΠΌΡΡ‚ΡŒ имя диска, доступноС Ρ‡Π΅Ρ€Π΅Π· Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ;
    • БохраняСм ΠΌΠ΅Ρ‚ΠΊΡƒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ.

  • РСгистрируСм kretprobe Π½Π° Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ ΠΈΠ· generic_make_request():
    • ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ ΠΌΠ΅Ρ‚ΠΊΡƒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ;
    • Π˜Ρ‰Π΅ΠΌ ΡΠΎΡ…Ρ€Π°Π½Π΅Π½Π½ΡƒΡŽ ΠΌΠ΅Ρ‚ΠΊΡƒ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ ΠΈ сравниваСм с Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ;
    • Если Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ большС Π·Π°Π΄Π°Π½Π½ΠΎΠ³ΠΎ, Ρ‚ΠΎ Π½Π°Ρ…ΠΎΠ΄ΠΈΠΌ сохранСнноС имя диска ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΠΌ Π½Π° Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π».

Kprobes ΠΈ kretprobes ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ Ρ‚ΠΎΡ‡Π΅ΠΊ останова для измСнСния ΠΊΠΎΠ΄Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ Π½Π° Π»Π΅Ρ‚Ρƒ. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΡŽ ΠΈ Ρ…ΠΎΡ€ΠΎΡˆΡƒΡŽ ΡΡ‚Π°Ρ‚ΡŒΡŽ Π½Π° эту Ρ‚Π΅ΠΌΡƒ. Если Π²Π·Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π½Π° ΠΊΠΎΠ΄ Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… ΡƒΡ‚ΠΈΠ»ΠΈΡ‚ Π² BCC, Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρƒ Π½ΠΈΡ… идСнтичная структура. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ Π² этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ опустим парсинг Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² скрипта ΠΈ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Π΅ΠΌ ΠΊ самой BPF ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ΅.

ВСкст eBPF Π²Π½ΡƒΡ‚Ρ€ΠΈ python-скрипта выглядит ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

bpf_text = β€œβ€β€ # Here will be the bpf program code β€œβ€β€

Для ΠΎΠ±ΠΌΠ΅Π½Π° Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ функциями, eBPF ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹. Π’Π°ΠΊ поступим ΠΈ ΠΌΡ‹. Π’ качСствС ΠΊΠ»ΡŽΡ‡Π° Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ PID процСсса, Π° Π² качСствС значСния ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ структуру:

struct data_t {
	u64 pid;
	u64 ts;
	char comm[TASK_COMM_LEN];
	u64 lat;
	char disk[DISK_NAME_LEN];
};

BPF_HASH(p, u64, struct data_t);
BPF_PERF_OUTPUT(events);

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ рСгистрируСм Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, которая называСтся p, с ΠΊΠ»ΡŽΡ‡ΠΎΠΌ Ρ‚ΠΈΠΏΠ° u64 ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ Ρ‚ΠΈΠΏΠ° struct data_t. Π’Π°Π±Π»ΠΈΡ†Π° Π±ΡƒΠ΄Π΅Ρ‚ доступна Π² контСкстС нашСй BPF-ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹. ΠœΠ°ΠΊΡ€ΠΎΡ BPF_PERF_OUTPUT рСгистрируСт Π΄Ρ€ΡƒΠ³ΡƒΡŽ Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡƒΡŽ events, которая ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Π² пространство ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

ΠŸΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Ρ€Π΅Π½ΠΈΠΈ Π·Π°Π΄Π΅Ρ€ΠΆΠ΅ΠΊ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ‹Π·ΠΎΠ²ΠΎΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ΠΎΠΌ ΠΈΠ· Π½Π΅Π΅, Π»ΠΈΠ±ΠΎ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ‹Π·ΠΎΠ²Π°ΠΌΠΈ Ρ€Π°Π·Π½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Π½ΡƒΠΆΠ½ΠΎ ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΡ€ΠΈΠ½Π°Π΄Π»Π΅ΠΆΠ°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎΠΌΡƒ контСксту. Π”Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠΌ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎΠΌ запускС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ. Π£ нас Π΅ΡΡ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΈΠ·ΠΌΠ΅Ρ€ΠΈΡ‚ΡŒ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ ΠΌΠ΅ΠΆΠ΄Ρƒ Π²Ρ‹Π·ΠΎΠ²ΠΎΠΌ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² контСкстС ΠΎΠ΄Π½ΠΎΠ³ΠΎ процСсса ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ΠΎΠΌ ΠΈΠ· этой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² контСкстС Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ процСсса, Π½ΠΎ это, скорСС всСго, бСсполСзно. Π₯ΠΎΡ€ΠΎΡˆΠΈΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠΌ здСсь ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠ»ΡƒΠΆΠΈΡ‚ΡŒ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Π° biolatency, Π³Π΄Π΅ Π² качСствС ΠΊΠ»ΡŽΡ‡Π° Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ задаСтся ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° struct request, которая ΠΎΡ‚Ρ€Π°ΠΆΠ°Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ запрос ΠΊ диску.

Π”Π°Π»Π΅Π΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒΡΡ ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ исслСдуСмой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ:

void start(struct pt_regs *ctx, struct bio *bio) {
	u64 pid = bpf_get_current_pid_tgid();
	struct data_t data = {};
	u64 ts = bpf_ktime_get_ns();
	data.pid = pid;
	data.ts = ts;
	bpf_probe_read_str(&data.disk, sizeof(data.disk), (void*)bio->bi_disk->disk_name);
	p.update(&pid, &data);
}

Π—Π΄Π΅ΡΡŒ Π² качСствС Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° Π±ΡƒΠ΄Π΅Ρ‚ подставлСн ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Π²Ρ‹Π·Π²Π°Π½Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ generic_make_request(). ПослС этого ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ PID процСсса, Π² контСкстС ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ, ΠΈ Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΌΠ΅Ρ‚ΠΊΡƒ Π² наносСкундах. ЗаписываСм это всё Π² ΡΠ²Π΅ΠΆΠ΅Π²Ρ‹Π΄Π΅Π»Π΅Π½Π½ΡƒΡŽ struct data_t data. Имя диска ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΈΠ· структуры bio, которая пСрСдаСтся ΠΏΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ generic_make_request(), ΠΈ сохраняСм Π΅Π³ΠΎ Π² Ρ‚Ρƒ ΠΆΠ΅ структуру data. ПослСдним шагом добавляСм запись Π² Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ, ΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π±Ρ‹Π»ΠΎ сказано Ρ€Π°Π½Π΅Π΅.

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ функция Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒΡΡ Π½Π° Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π΅ ΠΈΠ· generic_make_request():

void stop(struct pt_regs *ctx) {
    u64 pid = bpf_get_current_pid_tgid();
    u64 ts = bpf_ktime_get_ns();
    struct data_t* data = p.lookup(&pid);
    if (data != 0 && data->ts > 0) {
        bpf_get_current_comm(&data->comm, sizeof(data->comm));
        data->lat = (ts - data->ts)/1000;
        if (data->lat > MIN_US) {
            FACTOR
            data->pid >>= 32;
            events.perf_submit(ctx, data, sizeof(struct data_t));
        }
        p.delete(&pid);
    }
}

Π­Ρ‚Π° функция схоТа с ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ: ΡƒΠ·Π½Π°Π΅ΠΌ PID процСсса ΠΈ Π²Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ ΠΌΠ΅Ρ‚ΠΊΡƒ, Π½ΠΎ Π½Π΅ выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ ΠΏΠΎΠ΄ Π½ΠΎΠ²ΡƒΡŽ структуру data. ВмСсто этого ΠΌΡ‹ ΠΈΡ‰Π΅ΠΌ Π² Ρ…ΡΡˆ-Ρ‚Π°Π±Π»ΠΈΡ†Π΅ ΡƒΠΆΠ΅ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ структуру ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ == Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ PID. Если структура нашлась, Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠ·Π½Π°Π΅ΠΌ имя Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠ³ΠΎ процСсса ΠΈ добавляСм Π΅Π³ΠΎ Π² Π½Π΅Ρ‘.

Π‘ΠΈΠ½Π°Ρ€Π½Ρ‹ΠΉ сдвиг, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΡ‹ здСсь ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ, Π½ΡƒΠΆΠ΅Π½ для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ thread GID. Ρ‚.Π΅. PID основного процСсса, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ запустил ΠΏΠΎΡ‚ΠΎΠΊ, Π² контСкстС ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΡ‹ Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ. ВызываСмая Π½Π°ΠΌΠΈ функция bpf_get_current_pid_tgid() Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΊΠ°ΠΊ GID Ρ‚Ρ€Π΅Π΄Π°, Ρ‚Π°ΠΊ ΠΈ Π΅Π³ΠΎ PID Π² ΠΎΠ΄Π½ΠΎΠΌ 64-Π±ΠΈΡ‚Π½ΠΎΠΌ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΈ.

ΠŸΡ€ΠΈ Π²Ρ‹Π²ΠΎΠ΄Π΅ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» нас сСйчас Π½Π΅ интСрСсуСт ΠΏΠΎΡ‚ΠΎΠΊ, Π½ΠΎ интСрСсуСт основной процСсс. ПослС сравнСния ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΉ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ с Π·Π°Π΄Π°Π½Π½Ρ‹ΠΌ ΠΏΠΎΡ€ΠΎΠ³ΠΎΠΌ, ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ Π½Π°ΡˆΡƒ структуру data Π² пространство ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Ρ‡Π΅Ρ€Π΅Π· Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ events, послС Ρ‡Π΅Π³ΠΎ удаляСм запись ΠΈΠ· p.

Π’ python-скриптС, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹ΠΉ ΠΊΠΎΠ΄, Π½Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ MIN_US ΠΈ FACTOR Π½Π° ΠΏΠΎΡ€ΠΎΠ³ΠΈ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ ΠΈ Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΄ΠΈΠΌ Ρ‡Π΅Ρ€Π΅Π· Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹:

bpf_text = bpf_text.replace('MIN_US',str(min_usec))
if args.milliseconds:
	bpf_text = bpf_text.replace('FACTOR','data->lat /= 1000;')
	label = "msec"
else:
	bpf_text = bpf_text.replace('FACTOR','')
	label = "usec"

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ‚ΡŒ BPF ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ Ρ‡Π΅Ρ€Π΅Π· макрос BPF ΠΈ Π·Π°Ρ€Π΅Π³ΠΈΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ±Ρ‹:

b = BPF(text=bpf_text)
b.attach_kprobe(event="generic_make_request",fn_name="start")
b.attach_kretprobe(event="generic_make_request",fn_name="stop")

Π’Π°ΠΊΠΆΠ΅ Π½Π°ΠΌ придСтся ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ struct data_t Π² нашСм скриптС, ΠΈΠ½Π°Ρ‡Π΅ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ получится ΠΏΡ€ΠΎΡ‡Π΅ΡΡ‚ΡŒ:

TASK_COMM_LEN = 16	# linux/sched.h
DISK_NAME_LEN = 32	# linux/genhd.h
class Data(ct.Structure):
	_fields_ = [("pid", ct.c_ulonglong),
            	("ts", ct.c_ulonglong),
            	("comm", ct.c_char * TASK_COMM_LEN),
            	("lat", ct.c_ulonglong),
            	("disk",ct.c_char * DISK_NAME_LEN)]

ПослСдний шаг β€” Π²Ρ‹Π²ΠΎΠ΄ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»:

def print_event(cpu, data, size):
    global start
    event = ct.cast(data, ct.POINTER(Data)).contents
    if start == 0:
        start = event.ts
    time_s = (float(event.ts - start)) / 1000000000
    print("%-18.9f %-16s %-6d   %-1s %s   %s" % (time_s, event.comm, event.pid, event.lat, label, event.disk))

b["events"].open_perf_buffer(print_event)
# format output
start = 0
while 1:
    try:
        b.perf_buffer_poll()
    except KeyboardInterrupt:
        exit()

Π‘Π°ΠΌ скрипт доступСн Π½Π° GItHub. ΠŸΠΎΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Π΅Π³ΠΎ Π½Π° тСстовой ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅, Π³Π΄Π΅ Π·Π°ΠΏΡƒΡ‰Π΅Π½ fio, ΠΏΠΈΡˆΡƒΡ‰ΠΈΠΉ Π½Π° bcache, ΠΈ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ udevadm monitor:

ΠžΡ‚ High Ceph Latency ΠΊ Kernel Patch с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ eBPF/BCC
НаконСц-Ρ‚ΠΎ! Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ выглядСло ΠΊΠ°ΠΊ тормозящСС bcache-устройство, Π½Π° самом Π΄Π΅Π»Π΅ β€” тормозящий Π²Ρ‹Π·ΠΎΠ² generic_make_request() для ΠΊΡΡˆΠΈΡ€ΡƒΠ΅ΠΌΠΎΠ³ΠΎ диска.

Dig into the Kernel

Π§Ρ‚ΠΎ ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΡ‚ Π²ΠΎ врСмя ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ запроса? ΠœΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ° Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Π΄Π°ΠΆΠ΅ Π΄ΠΎ ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π½Π°Ρ‡Π°Π»Π° Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΈΠ½Π³Π° запроса, Ρ‚.Π΅. ΡƒΡ‡Π΅Ρ‚ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ запроса для дальнСйшСго Π²Ρ‹Π²ΠΎΠ΄Π° статистики ΠΏΠΎ Π½Π΅ΠΌΡƒ (/proc/diskstats ΠΈΠ»ΠΈ iostat) Π΅Ρ‰Ρ‘ Π½Π΅ начался. Π­Ρ‚ΠΎ Π»Π΅Π³ΠΊΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, запустив iostat Π²ΠΎ врСмя воспроизвСдСния ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹, Π»ΠΈΠ±ΠΎ BCC скрипт biolatency, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ основываСтся Π½Π° Π½Π°Ρ‡Π°Π»Π΅ ΠΈ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΠΈ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΈΠ½Π³Π° запросов. Ни ΠΎΠ΄Π½Π° ΠΈΠ· этих ΡƒΡ‚ΠΈΠ»ΠΈΡ‚ Π½Π΅ ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ для запросов ΠΊ ΠΊΠ΅ΡˆΠΈΡ€ΡƒΠ΅ΠΌΠΎΠΌΡƒ диску.

Если ΠΌΡ‹ взглянСм Π½Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ generic_make_request(), Ρ‚ΠΎ ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π΄ΠΎ Π½Π°Ρ‡Π°Π»Π° Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΈΠ½Π³Π° запроса Π²Ρ‹Π·Ρ‹Π²Π°ΡŽΡ‚ΡΡ Π΅Ρ‰Ρ‘ Π΄Π²Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. ΠŸΠ΅Ρ€Π²Π°Ρ β€” generic_make_request_checks(), выполняСт ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ лСгитимности запроса ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ настроСк диска. Вторая β€” blk_queue_enter(), Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π΅ΡΡ‚ΡŒ интСрСсный Π²Ρ‹Π·ΠΎΠ² wait_event_interruptible():

ret = wait_event_interruptible(q->mq_freeze_wq,
	(atomic_read(&q->mq_freeze_depth) == 0 &&
	(preempt || !blk_queue_preempt_only(q))) ||
	blk_queue_dying(q));

Π’ Π½Π΅ΠΌ ядро ΠΎΠΆΠΈΠ΄Π°Π΅Ρ‚ Ρ€Π°Π·ΠΌΠΎΡ€ΠΎΠ·ΠΊΠΈ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ. Π—Π°ΠΌΠ΅Ρ€ΠΈΠΌ Π·Π°Π΄Π΅Ρ€ΠΆΠΊΡƒ blk_queue_enter():

~# /usr/share/bcc/tools/funclatency  blk_queue_enter -i 1 -m               	 
Tracing 1 functions for "blk_queue_enter"... Hit Ctrl-C to end.

 	msecs           	: count 	distribution
     	0 -> 1      	: 341  	|****************************************|

 	msecs           	: count 	distribution
     	0 -> 1      	: 316  	|****************************************|

 	msecs           	: count 	distribution
     	0 -> 1      	: 255  	|****************************************|
     	2 -> 3      	: 0    	|                                    	|
     	4 -> 7      	: 0    	|                                    	|
     	8 -> 15     	: 1    	|                                    	|

ΠŸΠΎΡ…ΠΎΠΆΠ΅, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π±Π»ΠΈΠ·ΠΊΠΈ ΠΊ Ρ€Π°Π·Π³Π°Π΄ΠΊΠ΅. Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹Π΅ для Β«Π·Π°ΠΌΠΎΡ€ΠΎΠ·ΠΊΠΈ/Ρ€Π°Π·ΠΌΠΎΡ€ΠΎΠ·ΠΊΠΈΒ» ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ β€” это blk_mq_freeze_queue ΠΈ blk_mq_unfreeze_queue. Они ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Ρ‚ΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ настройки ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ запросов, ΠΏΠΎΡ‚Π΅Π½Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ опасныС для запросов, находящихся Π² этой ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ. ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ blk_mq_freeze_queue() Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ blk_freeze_queue_start() инкрСмСнтируСтся счСтчик q->mq_freeze_depth. ПослС этого ядро доТидаСтся ΠΎΠΏΡƒΡΡ‚ΠΎΡˆΠ΅Π½ΠΈΡ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ Π² blk_mq_freeze_queue_wait().

ВрСмя оТидания очистки этой ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ эквивалСнтно Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠ΅ диска, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ядро ΠΆΠ΄Π΅Ρ‚ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ выполнСния всСх поставлСнных Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ пустССт, ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ измСнСния настроСк. ПослС Ρ‡Π΅Π³ΠΎ вызываСтся blk_mq_unfreeze_queue(), Π΄Π΅ΠΊΡ€Π΅ΠΌΠ΅Π½Ρ‚ΠΈΡ€ΡƒΡŽΡ‰Π°Ρ счСтчик freeze_depth.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ Π·Π½Π°Π΅ΠΌ достаточно, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ. Команда udevadm trigger Π² Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π²Π΅Π΄Π΅Ρ‚ ΠΊ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΡŽ настроСк для Π±Π»ΠΎΡ‡Π½ΠΎΠ³ΠΎ устройства. Π­Ρ‚ΠΈ настройки описаны Π² ΠΏΡ€Π°Π²ΠΈΠ»Π°Ρ… udev. ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π½Π°ΠΉΡ‚ΠΈ, ΠΊΠ°ΠΊΠΈΠ΅ ΠΈΠΌΠ΅Π½Π½ΠΎ настройки Β«Π·Π°ΠΌΠΎΡ€Π°ΠΆΠΈΠ²Π°ΡŽΡ‚Β» ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Π² ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΈΡ… Ρ‡Π΅Ρ€Π΅Π· sysfs Π»ΠΈΠ±ΠΎ посмотрСв исходный ΠΊΠΎΠ΄ ядра. А Π΅Ρ‰Ρ‘ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠΏΡ€ΠΎΠ±ΠΎΠ²Π°Ρ‚ΡŒ ΡƒΡ‚ΠΈΠ»ΠΈΡ‚Ρƒ BCC trace, которая Π²Ρ‹Π²Π΅Π΄Π΅Ρ‚ Π½Π° Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» трСйсы стСка ядра ΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ пространства для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π° blk_freeze_queue, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

~# /usr/share/bcc/tools/trace blk_freeze_queue -K -U
PID 	TID 	COMM        	FUNC        	 
3809642 3809642 systemd-udevd   blk_freeze_queue
    	blk_freeze_queue+0x1 [kernel]
    	elevator_switch+0x29 [kernel]
    	elv_iosched_store+0x197 [kernel]
    	queue_attr_store+0x5c [kernel]
    	sysfs_kf_write+0x3c [kernel]
    	kernfs_fop_write+0x125 [kernel]
    	__vfs_write+0x1b [kernel]
    	vfs_write+0xb8 [kernel]
    	sys_write+0x55 [kernel]
    	do_syscall_64+0x73 [kernel]
    	entry_SYSCALL_64_after_hwframe+0x3d [kernel]
    	__write_nocancel+0x7 [libc-2.23.so]
    	[unknown]

3809631 3809631 systemd-udevd   blk_freeze_queue
    	blk_freeze_queue+0x1 [kernel]
    	queue_requests_store+0xb6 [kernel]
    	queue_attr_store+0x5c [kernel]
    	sysfs_kf_write+0x3c [kernel]
    	kernfs_fop_write+0x125 [kernel]
    	__vfs_write+0x1b [kernel]
    	vfs_write+0xb8 [kernel]
    	sys_write+0x55 [kernel]
    	do_syscall_64+0x73 [kernel]
    	entry_SYSCALL_64_after_hwframe+0x3d [kernel]
    	__write_nocancel+0x7 [libc-2.23.so]
    	[unknown]

Udev-ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ довольно Ρ€Π΅Π΄ΠΊΠΎ ΠΈ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ это происходит ΠΏΠΎΠ΄ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒΠ½ΠΎ. Π’Π°ΠΊ Ρ‡Ρ‚ΠΎ ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π΄Π°ΠΆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΡƒΠΆΠ΅ Π·Π°Π΄Π°Π½Π½Ρ‹Ρ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ всплСск Π·Π°Π΄Π΅Ρ€ΠΆΠΊΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ запроса ΠΎΡ‚ прилоТСния диску. ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ udev-события, ΠΊΠΎΠ³Π΄Π° Π½Π΅Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠΈΡ… ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ Π² ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ дисков (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, устройство Π½Π΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ/ΠΎΡ‚ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ), Π½Π΅ ΠΎΡ‡Π΅Π½ΡŒ Ρ…ΠΎΡ€ΠΎΡˆΠ°Ρ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠ°. Π’Π΅ΠΌ Π½Π΅ ΠΌΠ΅Π½Π΅Π΅, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠΌΠΎΡ‡ΡŒ ядру Π½Π΅ Π΄Π΅Π»Π°Ρ‚ΡŒ бСсполСзной Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈ Π½Π΅ Β«Π·Π°ΠΌΠΎΡ€Π°ΠΆΠΈΠ²Π°Ρ‚ΡŒΒ» ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ запросов, Ссли Π² этом Π½Π΅Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠΎΠΉ нСобходимости. Π’Ρ€ΠΈ ΠΌΠ°Π»Π΅Π½ΡŒΠΊΠΈΡ… ΠΊΠΎΠΌΠΌΠΈΡ‚Π° ΠΈΡΠΏΡ€Π°Π²Π»ΡΡŽΡ‚ ΡΠΈΡ‚ΡƒΠ°Ρ†ΠΈΡŽ.

Conclusion

eBPF β€” это ΠΎΡ‡Π΅Π½ΡŒ Π³ΠΈΠ±ΠΊΠΈΠΉ ΠΈ ΠΌΠΎΡ‰Π½Ρ‹ΠΉ инструмСнт. Π’ ΡΡ‚Π°Ρ‚ΡŒΠ΅ ΠΌΡ‹ рассмотрСли ΠΎΠ΄ΠΈΠ½ практичСский кСйс ΠΈ продСмонстрировали ΠΌΠ°Π»ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ. Если Π²Π°ΠΌ интСрСсна Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° BCC-ΡƒΡ‚ΠΈΠ»ΠΈΡ‚, стоит Π²Π·Π³Π»ΡΠ½ΡƒΡ‚ΡŒ Π½Π° ΠΎΡ„ΠΈΡ†ΠΈΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π», ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ…ΠΎΡ€ΠΎΡˆΠΎ описываСт основы Ρ€Π°Π±ΠΎΡ‚Ρ‹.

Π•ΡΡ‚ΡŒ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ интСрСсныС инструмСнты для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ ΠΈ профилирования, основанныС Π½Π° eBPF. Один ΠΈΠ· Π½ΠΈΡ… β€” bpftrace, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΌΠΎΡ‰Π½Ρ‹Π΅ однострочники ΠΈ малСнькиС ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΊΠΈ Π½Π° awk-like языкС. Π”Ρ€ΡƒΠ³ΠΎΠΉ β€” ebpf_exporter, позволяСт ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹Π΅ ΠΌΠ΅Ρ‚Ρ€ΠΈΠΊΠΈ высокого Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ прямо Π² ваш prometheus сСрвСр, с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ Π² дальнСйшСм ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΊΡ€Π°ΡΠΈΠ²ΡƒΡŽ Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΈ Π΄Π°ΠΆΠ΅ Π°Π»Π΅Ρ€Ρ‚Ρ‹.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com