Tina High Ceph Latency ka Kernel Patch nganggo eBPF / BCC

Tina High Ceph Latency ka Kernel Patch nganggo eBPF / BCC

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 alat sejen geus dimekarkeun - eBPF. Éta ngamungkinkeun pikeun ngalacak kernel sareng aplikasi pangguna kalayan overhead rendah sareng tanpa kedah ngawangun deui program sareng ngamuat modul pihak katilu kana kernel.

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. PythonBCC. Artikel ieu dumasar kana kajadian nyata. Urang bakal balik tina masalah pikeun ngalereskeun pikeun nunjukkeun kumaha utilitas anu tos aya tiasa dianggo dina kaayaan khusus.

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.

Tina High Ceph Latency ka Kernel Patch nganggo eBPF / BCC
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 parfum и flamescope (Langkung seueur ngeunaan anu anjeun tiasa baca di dieu):

Tina High Ceph Latency ka Kernel Patch nganggo eBPF / BCC
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 BCC Geus aya utilitas anu saé - fungsina. Urang bakal ngalacak daemon ku PID na sareng interval 1 detik antara kaluaran sareng kaluaran hasilna dina milidetik.

Tina High Ceph Latency ka Kernel Patch nganggo eBPF / BCC
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 BCC utiliti kit. Hayu urang ngajalankeun eta sarta ngirim kaluaran ka file a.

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 dokuméntasi и alus artikel dina topik ieu. Lamun nempo kodeu rupa Utiliti di BCC, teras anjeun tiasa ningali yén aranjeunna gaduh struktur anu sami. Janten dina tulisan ieu urang bakal ngalangkungan argumen naskah parsing sareng teraskeun kana program BPF sorangan.

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 tabél hash. Urang bakal lakonan hal nu sarua. Urang bakal ngagunakeun prosés PID salaku konci, sarta nangtukeun struktur salaku nilai:

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 pangiriman data kana rohangan pamaké.

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 utiliti biolatency, dimana konci tabel hash disetel ka pointer ka pamundut struct, nu ngagambarkeun hiji pamundut disk.

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 generic_make_request(). Saatos ieu, urang nampi PID tina prosés dina kontéks anu urang damel, sareng timestamp ayeuna dina nanoseconds. Urang nulis eta kabeh handap dina Freshly dipilih struct data_t data. Kami nampi nami disk tina strukturna bio, anu diliwatan nalika nelepon generic_make_request(), sareng simpen dina struktur anu sami data. Léngkah terakhir nyaéta nambihan éntri kana méja hash anu disebatkeun tadi.

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 bpf_get_current_pid_tgid() mulih duanana GID thread na PID na dina nilai 64-bit tunggal.

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 BPF makro sareng ngadaptarkeun conto:

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 GItHub. Hayu urang cobian ngajalankeun éta dina platform uji dimana fio jalan, nyerat kana bcache, sareng nelepon monitor udevadm:

Tina High Ceph Latency ka Kernel Patch nganggo eBPF / BCC
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 Biolatency Aksara BCC, nu dumasar kana mimiti jeung ahir akuntansi pamundut. Euweuh sahiji utilitas ieu bakal nembongkeun masalah pikeun requests ka disk sindangan.

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- blk_queue_enter(), nu boga tantangan metot 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));

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 blk_mq_freeze_queue и blk_mq_unfreeze_queue. Éta téh dipaké nalika perlu ngarobah setelan antrian pamundut, nu berpotensi bahaya pikeun requests dina antrian ieu. Nalika nelepon blk_mq_freeze_queue() fungsi blk_freeze_queue_start() counter ieu incremented q->mq_freeze_depth. Saatos ieu, kernel ngantosan antrian kosong blk_mq_freeze_queue_wait().

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 blk_mq_unfreeze_queue(), decrementing counter freeze_depth.

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 renik, nu bakal kaluaran kernel na userspace tumpukan ngambah keur unggal panggero ka terminal blk_freeze_queueContona:

~# /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. tilu leutik komitmen ngabenerkeun kaayaan.

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 tutorial resmi, anu ngajelaskeun dasarna ogé.

Aya alat debugging sareng profiling anu sanés dumasar kana eBPF. Salah sahijina - bpftrace, nu ngidinan Anjeun pikeun nulis kuat hiji-liners jeung program leutik dina basa awk-kawas. Lian - ebpf_exporter, ngidinan Anjeun pikeun ngumpulkeun-tingkat low, metrics resolusi luhur langsung kana server prometheus anjeun, kalawan kamampuhan pikeun engké meunang visualizations geulis komo ngabejaan.

sumber: www.habr.com

Tambahkeun komentar