Linux Ubuntu gaduh sajumlah ageung alat pikeun debugging kernel sareng aplikasi. Kaseueuran aranjeunna gaduh dampak negatif kana kinerja aplikasi sareng henteu tiasa dianggo dina produksi.
Sababaraha taun ka pengker aya
Geus aya seueur utilitas aplikasi anu nganggo eBPF, sareng dina tulisan ieu kami bakal ningali kumaha cara nyerat utilitas profil anjeun sorangan dumasar kana perpustakaan.
Ceph Is Slow
A host anyar geus ditambahkeun kana klaster Ceph. Saatos migrasi sababaraha data ka dinya, urang noticed nu laju ngolah requests nulis ku éta leuwih handap ti on server séjén.
Beda sareng platform anu sanés, host ieu nganggo bcache sareng kernel linux 4.15 énggal. Ieu kahiji waktos host konfigurasi ieu dipaké di dieu. Sareng dina waktos éta écés yén akar masalah sacara téoritis tiasa janten nanaon.
Nalungtik Host
Hayu urang mimitian ku ningali naon anu lumangsung dina prosés ceph-osd. Pikeun ieu kami bakal ngagunakeun
gambar ngabejaan urang yen fungsi fdatasync() spent loba waktu ngirim pamundut ka fungsi generic_make_request(). Ieu ngandung harti yén paling dipikaresep cukang lantaranana masalah aya di luar daemon osd sorangan. Ieu tiasa janten kernel atanapi disk. Kaluaran iostat nunjukkeun latency anu luhur dina ngolah pamundut ku disk bcache.
Nalika mariksa host, kami mendakan yén daemon systemd-udevd nyéépkeun waktos CPU anu ageung - sakitar 20% dina sababaraha inti. Ieu kabiasaan aneh, jadi Anjeun kudu manggihan naha. Kusabab Systemd-udevd jalan kalawan uevents, urang mutuskeun pikeun nempo aranjeunna ngaliwatan monitor udevadm. Tétéla yén sajumlah ageung acara parobihan dibangkitkeun pikeun unggal alat blok dina sistem. Ieu rada mahiwal, jadi urang kudu kasampak di naon dibangkitkeun sagala acara ieu.
Ngagunakeun BCC Toolkit
Sakumaha anu parantos urang terangkeun, kernel (sareng daemon ceph dina telepon sistem) nyéépkeun seueur waktos dina generic_make_request(). Hayu urang coba ngukur laju fungsi ieu. DI
Fitur ieu biasana jalan gancang. Sadayana nyaéta ngalangkungan pamundut ka antrian supir alat.
Bcache mangrupakeun alat kompléks nu sabenerna diwangun ku tilu disk:
- alat backing (cached disk), dina hal ieu mangrupa HDD slow;
- alat cache (caching disk), didieu ieu salah sahiji partisi alat NVMe;
- alat maya bcache nu ngajalankeun aplikasi.
Urang terang yén pangiriman pamundut lambat, tapi pikeun alat ieu? Urang bakal nungkulan ieu saeutik engké.
Urang ayeuna terang yén uevents kamungkinan ngabalukarkeun masalah. Milarian naon anu nyababkeun generasina henteu gampang. Hayu urang nganggap yén ieu mangrupikeun sababaraha jinis parangkat lunak anu diluncurkeun sacara périodik. Hayu urang tingali jinis parangkat lunak anu dijalankeun dina sistem nganggo skrip execsnoop ti sarua
Contona saperti kieu:
/usr/share/bcc/tools/execsnoop | tee ./execdump
Kami moal nunjukkeun kaluaran pinuh ku execsnoop di dieu, tapi hiji garis anu dipikaresep ku urang katingali sapertos kieu:
sh 1764905 5802 0 sudo arcconf getconfig 1 AD | grep Temperature | awk -F '[:/]' '{print $2}' | sed 's/^ ([0-9]*) C.*/1/'
Kolom katilu nyaéta PPID (indungna PID) prosés. Prosés sareng PID 5802 tétéla janten salah sahiji utas sistem ngawaskeun kami. Nalika mariksa konfigurasi sistem ngawaskeun, paraméter anu salah kapanggih. Suhu adaptor HBA dicandak unggal 30 detik, anu langkung sering ti anu diperyogikeun. Saatos ngarobih interval cek ka anu langkung panjang, kami mendakan yén latency ngolah pamundut dina host ieu henteu deui nangtung dibandingkeun host anu sanés.
Tapi masih can écés naha alat bcache éta jadi slow. Urang disiapkeun platform test kalawan konfigurasi idéntik jeung nyoba baranahan masalah ku ngajalankeun fio on bcache, périodik ngajalankeun udevadm pemicu pikeun ngahasilkeun uevents.
Nulis Pakakas basis BCC
Hayu urang cobian nyerat utilitas saderhana pikeun ngalacak sareng ningalikeun telepon anu paling laun generic_make_request(). Urang ogé museurkeun nami drive nu fungsi ieu disebut.
Rencanana saderhana:
- Ngadaptar kprobe dina generic_make_request():
- Urang nyimpen nami disk kana mémori, diaksés ngaliwatan argumen fungsi;
- Urang nyimpen timestamp.
- Ngadaptar kretprobe pikeun mulang ti generic_make_request():
- Simkuring meunang timestamp ayeuna;
- Kami milarian timestamp anu disimpen sareng ngabandingkeunana sareng anu ayeuna;
- Upami hasilna langkung ageung tibatan anu ditangtukeun, maka urang mendakan nami disk anu disimpen sareng nampilkeunana dina terminal.
Kprobes и kretprobes ngagunakeun mékanisme breakpoint pikeun ngarobah kodeu fungsi dina laleur nu. Anjeun tiasa maca
Téks eBPF di jero skrip python sapertos kieu:
bpf_text = “”” # Here will be the bpf program code “””
Pikeun tukeur data antara fungsi, program eBPF ngagunakeun
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);
Di dieu urang ngadaptarkeun tabel hash disebut p, kalawan tipe konci u64 sarta nilai tipe struct data_t. tabél bakal sadia dina konteks program BPF urang. BPF_PERF_OUTPUT makro registers tabel séjén disebut kajadian, nu dipaké pikeun
Nalika ngukur telat antara nelepon hiji fungsi jeung balik ti dinya, atawa antara nelepon ka fungsi béda, Anjeun kudu tumut kana akun yén data nu narima kudu milik konteks sarua. Dina basa sejen, Anjeun kudu inget ngeunaan kamungkinan peluncuran paralel fungsi. Urang miboga kamampuh pikeun ngukur latency antara nelepon hiji fungsi dina konteks hiji prosés jeung balik ti fungsi nu dina konteks prosés sejen, tapi ieu kamungkinan aya gunana. Hiji conto alus didieu bakal
Salajengna, urang kedah nyerat kodeu anu bakal dijalankeun nalika fungsi anu ditalungtik disebut:
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);
}
Di dieu argumen kahiji tina fungsi disebut bakal diganti salaku argumen kadua
Fungsi handap bakal disebut dina balik ti 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);
}
}
Pungsi ieu sarupa jeung saméméhna: urang manggihan PID tina prosés jeung timestamp, tapi teu allocate memori pikeun struktur data anyar. Gantina, urang milarian tabel hash pikeun struktur anu tos aya nganggo konci == PID ayeuna. Upami strukturna kapanggih, maka urang terangkeun nami prosés jalanna sareng tambahkeunana.
Pergeseran binér anu kami anggo di dieu diperyogikeun pikeun kéngingkeun benang GID. jelema. PID tina prosés utama anu ngamimitian benang dina kontéks anu urang damel. Fungsi urang nelepon
Nalika kaluaran ka terminal, urang ayeuna henteu kabetot dina benang, tapi urang museurkeun prosés utama. Saatos ngabandingkeun tunda anu hasilna sareng ambang anu dipasihkeun, urang lulus struktur urang data kana rohangan pamaké via méja kajadian, sanggeus éta urang mupus entri ti p.
Dina skrip python anu bakal ngamuat kode ieu, urang kedah ngagentos MIN_US sareng FACTOR kalayan ambang reureuh sareng unit waktos, anu bakal kami lebetkeun argumen:
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"
Ayeuna urang kedah nyiapkeun program BPF via
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")
Urang ogé kudu nangtukeun struct data_t dina naskah urang, disebutkeun urang moal bisa maca nanaon:
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)]
Léngkah terakhir nyaéta ngaluarkeun data ka terminal:
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()
Aksara sorangan sadia di
Tungtungna! Ayeuna urang tingali yén anu katingali sapertos alat bcache anu stalling saleresna mangrupikeun telepon anu macet generic_make_request() pikeun disk sindangan.
Ngali kernel
Naon kahayang anu ngalambatkeun nalika pangiriman pamundut? Urang nempo yén reureuh lumangsung malah saméméh mimiti akuntansi pamundut, i.e. akuntansi ngeunaan pamundut husus pikeun kaluaran salajengna tina statistik dina eta (/ proc / diskstats atanapi iostat) teu acan dimimitian. Ieu bisa gampang diverifikasi ku ngajalankeun iostat bari reproducing masalah, atawa
Lamun urang nempo fungsi generic_make_request(), teras urang bakal ningali yén sateuacan pamenta ngamimitian akuntansi, dua fungsi deui disebut. kahiji- generic_make_request_checks(), ngalakukeun cék dina legitimasi pamundut ngeunaan setélan disk. Kadua-
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));
Di jerona, kernel ngantosan antrian unfreeze. Hayu urang ngukur reureuh 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 | |
Sigana urang nuju caket kana solusi. Fungsi nu dipaké pikeun freeze / unfreeze antrian nyaeta
Waktu nu diperlukeun pikeun mupus antrian ieu sarua jeung latency disk salaku kernel ngantosan sagala operasi antrian réngsé. Sakali antrian kosong, parobahan setélan diterapkeun. Sanggeus éta disebut
Ayeuna urang terang cukup pikeun ngabenerkeun kaayaan. Paréntah pemicu udevadm ngabalukarkeun setelan pikeun alat block diterapkeun. Setélan ieu dijelaskeun dina aturan udev. Urang tiasa mendakan setélan mana anu katirisan antrian ku nyobian ngarobihna ngaliwatan sysfs atanapi ku ningali kode sumber kernel. Urang ogé tiasa nyobian utilitas BCC
~# /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]
Aturan Udev jarang robih sareng biasana ieu kajantenan sacara terkendali. Janten urang ningali yén sanajan nerapkeun nilai anu parantos disetél ngabalukarkeun spike dina reureuh dina nransferkeun pamundut ti aplikasi ka disk. Tangtu, generating acara udev lamun euweuh parobahan dina konfigurasi disk (Contona, alat teu dipasang / dipegatkeun) teu prakték alus. Nanging, urang tiasa ngabantosan kernel henteu ngalakukeun padamelan anu teu perlu sareng ngabekukeun antrian pamundut upami henteu diperyogikeun.
kacindekan
eBPF mangrupikeun alat anu fleksibel sareng kuat. Dina artikel urang nempo hiji hal praktis tur nunjukkeun bagian leutik tina naon bisa dipigawé. Upami anjeun resep ngembangkeun utilitas BCC, éta patut ditingali
Aya alat debugging sareng profiling anu sanés dumasar kana eBPF. Salah sahijina -
sumber: www.habr.com