Ex High Ceph Latency ad Kernel Patch usura eBPF/BCC

Ex High Ceph Latency ad Kernel Patch usura eBPF/BCC

Linux magnum numerum instrumentorum habet ad debugging nucleum et applicationes. Plerique eorum negativam habent in effectu applicationis et in productione adhiberi non possunt.

A duobus annos erat aliud instrumentum est developed β€” eBPF. Efficit ut nucleum et usorem applicationes per caput humile investigare possit et sine necessitate programmata reficere et tertiam partem modulorum in nucleum onerare.

Iam multae sunt applicationes utilitates quae eBPF utuntur, et in hoc articulo videbimus quomodo scribere utilitatem tuam in bibliotheca profiling. PythonBCC. Articulus certitudinum rerum fundatur. Ex problemate venimus ut figere monstraremus quomodo exsistentes utilitates in certis adiunctis adhiberi possint.

Ceph tarda

Ad Ceph botrum nova hostia addita est. Postquam nonnullae notitiae ad eam migrarunt, animadvertimus celeritatem processus scribendi petitiones multo inferiores esse quam in aliis servientibus.

Ex High Ceph Latency ad Kernel Patch usura eBPF/BCC
Dissimilis alia tabulata, hospes hic bcache usus est et nova linux 4.15 nucleus. Hoc primum hospita huius configurationis adhibita est. Et tunc apparebat radicem problematis posse speculari aliquid esse.

Hostiam perscrutandis

Incipiamus aspicere quid intra processum Ceph-osd fiat. Hoc enim utemur perfectus ΠΈ flamescope (Plura de quibus legere potes hic):

Ex High Ceph Latency ad Kernel Patch usura eBPF/BCC
Imago docet munus fdatasync () Multum temporis consumpta petentibus munera generic_make_request (). Hoc significat verisimile causam problematum alicubi esse extra ipsum daemonem osd. Hoc vel acinum vel orbis esse potest. Iostat output ostendit altam latentiam in processu petitionibus per orbes subcinericios.

Cum exercitum reprehendo, invenimus daemonem systemd-udevd magnam quantitatem temporis CPU - circiter XX% in aliquot nucleis consumere. Moribus mirum est, sic debes cognoscere quare. Cum Systemd-udevd opera cum uevents, ea perspicere decrevimus udevadm monitor. Evenit ut magnus numerus mutationum eventuum pro unoquoque stipite in systematis fabrica generaretur. Hoc satis inusitatum est, ut inspicere debebimus haec omnia generantem eventa.

BCC Toolkit utens

Ut iam compertum est, nucleus (et ceph daemoniacus in systemate vocatus) multum temporis impendit in generic_make_request (). Studeamus celeritatem huius muneris metiri. IN' BCC Mira iam est utilitas - funclatency. Daemonem suo PID cum secundo intervallo 1 inter outputs et output eventus in milliseconds secundorum intervallo investigabimus.

Ex High Ceph Latency ad Kernel Patch usura eBPF/BCC
Pluma celeriter operatur plerumque. Omnia facit ad petitionem fabrica coegi queue transiet.

Bcache est complexus fabrica quae consistit in tribus orbis:

  • in hoc casu lento HDD est;
  • caching fabrica (caching disk), hic haec est una partitio NVMe fabrica;
  • bcache virtualis fabrica quo applicatio decurrit.

Scimus quod petitio tradenda tardum est, sed uter horum machinis? De hoc paulo post agemus.

Nunc scimus ueventa causa problemata esse verisimile. Quaenam earum generatio non tam facile causat. Ponamus hanc esse speciem aliquam programmatum quae periodice immissa est. Videamus quid genus programmatum currit in systemate utendi scripto execsnoop ex eodem BCC utilitatem ornamentum. Curramus eum et ad limam mittat output.

Exempli gratia sic:

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

Plenum execsnoop hic exitum non demonstrabimus, sed una linea usuris nobis sic visa est:

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

Tertia columna est PPID (parentis PID) processus. Processus cum PID 5802 evasit unum e sequelis systematis nostrae vigilantiae. Cum de configuratione magna ratio deprimenda, parametri erronei inventi sunt. Temperatura adaptoris HBA singulis 30 secundis capta est, quae multo saepius quam necesse est. Mutata perscriptio temporis ad longiorem, invenimus petitionem processus latendi in hoc exercitu non amplius prominens cum aliis exercitibus.

Sed adhuc incertum est cur bcache fabrica tam tardus sit. Praeparavimus testam suggestum cum identitate configurationis et conati sunt exprimere problema currendo fio in bcache, intervenit felis udevadm currens ad generandum uevents.

Scribens BCC-Substructio Tools

Studeamus scribere utilitatem simplicem indagare et tardissimam vocat ostendere generic_make_request (). Nos quoque quaero nomine coegi pro quo hoc munus appellabatur.

Consilium simplex est;

  • Register kprobe on generic_make_request ():
    • Nomen orbis servamus in memoriam, pervium per munus argumentum;
    • Nulla in tincidunt nisi.

  • Register kretprobe nam reditus ex * generic_make_request ():
    • Praesens indicationem obtinemus;
    • Indicationem servatam exspectamus et cum hodierna comparamus;
    • Si effectus maior est quam determinatum, tunc nomen orbis servatum invenimus et in termino demonstrabimus.

Kprobes ΠΈ kretprobes utor a mechanism breakpoint ad mutationem functionis codicem in musca. Potes legere Litterarum ΠΈ bonum articulum de hoc argumento. Si codicem variarum utilitatium spectes BCCtunc videre potes eandem habere structuram. In hoc articulo igitur argumenta scriptorum parsing praetermittemus et ad ipsum propositum BPF transibimus.

Textus eBPF intra scriptionem Pythonis hoc modo spectat:

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

Ad commutationem notitia inter munera, programmata eBPF Nullam tables. Idem faciemus. Processus PID ut clavis utemur, structuram ut valorem definiemus;

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);

Hic subcriptio tabulam Nullam dicta pCum clavem type u64 et valorem generis instruere data_t. Mensa in contextu programmatis BPF praesto erit. BPF_PERF_OUTPUT tabulam tortor aliam tabulam quae vocatur rerum, quod ponitur pro notitia tradenda in user spatium.

Cum moras metiaris inter vocans munus et inde reverti, vel inter vocationes ad diversa munera, considerare debes data recepta ad eundem contextum pertinere. Aliis verbis, meminisse debes de functionibus parallelis possibilibus. Facultatem habemus latency metiri inter munus vocandi in contextu unius processus et ab illo munere in contextum alterius processus reverti, sed hoc verisimile inutile est. Exemplum bonum hic erit biolatency utilitatem, Ubi clavem mensam Nullam monstratori apponitur instrΓΊite petitionem, quod unum disci petat.

Deinceps scribendus est codicem qui decurret cum munus sub studio appellatur;

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);
}

Prima ratio functionis vocati hic substituetur pro secundo argumento generic_make_request (). Post hoc processum PID obtinemus in contextu cuius operamur, et temporis instantis in nanoseconds. Scribimus omnia in recentibus delectis instruere data_t data. Nos adepto a structuram nomen orbis Bioquod fit cum vocatione generic_make_request ()et in eadem structura serva illum Data. Ultimus gradus est accessum ad tabulam detrahere, de qua prius dictum est.

Munus sequens vocabitur in reditu a 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);
    }
}

Hoc munus priori simile est: invenimus PID processus et indicatione, sed memoriam pro nova data structura non collocant. Sed quaerimus tabulam detrahere pro structura iam exsistente clavis == currenti PID. Si structura inveniatur, inueniemus nomen processus currens et adiciemus ei.

Trabea binaria hic utimur necesse est ut filum GID accipiamus. illae. PID processus principalis, qui filum incepit in contextu cuius operamur. Munus vocamus bpf_get_current_pid_tgid () redit et stamina GID et eius PID in uno 64-bit pretii.

Cum terminatio ad terminum, non currently in flumine quaeritur, sed in processu principali interest. Ubi morae inde comparato dato limine, structuram nostram transeamus Data in user spatium per mensam rerum, post quod ingressum delemus e p.

In pythonis scriptione quae hunc codicem oneret, MIN_US et factor in mora liminum ac temporum unitates reponere necesse est, quae per argumenta transibimus:

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"

Nunc opus est programmata BPF praeparare per BPF macro et exempla subcriptio:

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")

Volumus etiam determinare instruere data_t in nostro scripto, aliter aliquid legere non valemus;

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)]

Ultimus gradus est notitia output ad terminum:

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()

Scriptum est ipsum at GItHub. Conemur currere in testi suggestu ubi fio currit, scribens ad bcache, et monitor udevadm voca;

Ex High Ceph Latency ad Kernel Patch usura eBPF/BCC
Denique! Videmus autem quod quasi fabrica stabularii beache machinam vocamus actualiter generic_make_request () conditivo in disco.

Fode in Kernel

Quidnam retardatio in petitione tradenda? Moram fieri videmus etiam ante rationem petitionis initium, i.e. de ratione petitionis specificae statisticae ulterioris output in ea (/proc/diskstats vel iostat) nondum incohata est. Hoc facile verificatur per currendo iostat producendo problema, vel BCC script biolatency, quod innititur in principio et fine petitionis ratiocinandi. Nulla harum utilitatum problemata pro petitionibus orbis conditivo ostendet.

Si munus intueri generic_make_request ()tunc videbimus quod antequam petitio incipit ratiocinari, plura duo functiones vocantur. Primis - generic_make_request_checks ()peragit impediunt legitimam petitionem circa ordines orbis. Secundus - blk_queue_enter()quae interesting provocatio 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));

In ea, nucleus exspectat queue ut ungatur. Metimur mora 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    	|                                    	|

Similis sumus prope solutionem. Munera ad durandam / unfreeze a queue are blk_mq_freeze_queue ΠΈ blk_mq_unfreeze_queue. Adhibentur, cum necesse est ut occasus queue petentibus mutes, quae in hac queue petitiones potentia periculosa sunt. cum vocantem blk_mq_freeze_queue () officium blk_freeze_queue_start() contra est z q> mq_freeze_depth. Post haec, nucleus observat queue vacuam blk_mq_freeze_queue_wait ().

Tempus accipit ut hanc queue purgandam aequivalet discri latency sicut nucleus omnes operationes amet exspectationes ad perficiendum. Queue olim vacua est, occasus mutationes applicantur. Post quem dicitur blk_mq_unfreeze_queue ()Decernens contra freeze_depth.

Nunc satis scimus ad rem emendandam. In udevadm felis mandatum facit uncinis ad fabricam applicandam. Hae uncinis describuntur in regulis udev. Invenire possumus qui occasus queue constringunt quaerendo eas per sysfs mutare vel ad fontem nuclei codicem intuendo. Possumus etiam experiri BCC utilitatem vestigium, quod nucleum et usorspace ACERVUM output erit vestigium uniuscuiusque vocationis ad terminalem blk_freeze_queueFor example:

~# /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]

Regulae Udev admodum raro mutantur, ac plerumque hoc modo moderato eveniunt. Perspicimus igitur etiam applicando valores iam statutos spicam in mora transferendi postulationem ab applicatione in disco. Utique udev generans eventus, cum nullae sunt mutationes in figura orbis (exempli gratia, fabrica non ascendit/disiuncta) non bene usus est. Sed nucleum adiuvare possumus non opus facere superfluum et durare petitionem queue si non est necesse. tribus Parvus committere corrigere transp.

Conclusio

eBPF est instrumentum flexibile et validum. In uno casu practico inspeximus articulum, et demonstravimus particulam quid fieri possit. Si vos es interested in explicando BCC utilitates, suus 'vultus captus officialis Nullamqui fundamenta bene describit.

Aliae res commodae debugging et profilingunt instrumenta quae in eBPF nituntur. Unus eorum - bpftracequae permittit tibi scribere validissimas et parvas programmata in sermone varico. Alius - ebpf_exporter, sino te colligere humilem , altam solutionem metricam directe in tuum prometheum cultorem , cum facultate ut postea pulchras visualizationes et etiam erectas possideas .

Source: www.habr.com