Mae gan Linux nifer fawr o offer ar gyfer dadfygio'r cnewyllyn a'r cymwysiadau. Mae'r rhan fwyaf ohonynt yn cael effaith negyddol ar berfformiad y cais ac ni ellir eu defnyddio wrth gynhyrchu.
Ychydig flynyddoedd yn Γ΄l roedd yna
Mae yna lawer o gyfleustodau cymhwysiad eisoes sy'n defnyddio eBPF, ac yn yr erthygl hon byddwn yn edrych ar sut i ysgrifennu eich cyfleustodau proffilio eich hun yn seiliedig ar y llyfrgell
Ceph Yn Araf
Mae gwesteiwr newydd wedi'i ychwanegu at glwstwr Ceph. Ar Γ΄l mudo peth o'r data iddo, gwnaethom sylwi bod cyflymder prosesu ceisiadau ysgrifennu ganddo yn llawer is nag ar weinyddion eraill.
Yn wahanol i lwyfannau eraill, defnyddiodd y gwesteiwr hwn bcache a'r cnewyllyn linux 4.15 newydd. Dyma'r tro cyntaf i lu o'r cyfluniad hwn gael ei ddefnyddio yma. Ac ar y foment honno roedd yn amlwg y gallai gwraidd y broblem fod yn unrhyw beth yn ddamcaniaethol.
Ymchwilio i'r Gwesteiwr
Gadewch i ni ddechrau trwy edrych ar yr hyn sy'n digwydd y tu mewn i'r broses ceph-osd. Ar gyfer hyn byddwn yn defnyddio
Mae'r llun yn dweud wrthym fod y swyddogaeth fdatasync() treulio llawer o amser yn anfon cais i swyddogaethau cais_gwneud_generig(). Mae hyn yn golygu mai rhywle y tu allan i'r ellyll osd ei hun sydd fwyaf tebygol o achosi'r problemau. Gall hyn fod naill ai'r cnewyllyn neu ddisgiau. Roedd allbwn yr iostat yn dangos llawer o hwyrni wrth brosesu ceisiadau gan ddisgiau bcache.
Wrth wirio'r gwesteiwr, canfuom fod yr daemon systemd-udevd yn defnyddio llawer iawn o amser CPU - tua 20% ar sawl craidd. Mae hwn yn ymddygiad rhyfedd, felly mae angen i chi ddarganfod pam. Gan fod Systemd-udevd yn gweithio gyda uevents, penderfynasom edrych arnynt drwodd monitor udevadm. Mae'n ymddangos bod nifer fawr o ddigwyddiadau newid wedi'u cynhyrchu ar gyfer pob dyfais bloc yn y system. Mae hyn yn eithaf anarferol, felly bydd yn rhaid i ni edrych ar yr hyn sy'n cynhyrchu'r holl ddigwyddiadau hyn.
Defnyddio Pecyn Cymorth BCC
Fel yr ydym eisoes wedi darganfod, mae'r cnewyllyn (a'r ellyll ceph yn yr alwad system) yn treulio llawer o amser yn cais_gwneud_generig(). Gadewch i ni geisio mesur cyflymder y swyddogaeth hon. YN
Mae'r nodwedd hon fel arfer yn gweithio'n gyflym. Y cyfan y mae'n ei wneud yw trosglwyddo'r cais i'r ciw gyrrwr dyfais.
Bcache yn ddyfais gymhleth sydd mewn gwirionedd yn cynnwys tair disg:
- dyfais gefn (disg wedi'i storio), yn yr achos hwn mae'n HDD araf;
- dyfais caching (disg caching), dyma un rhaniad o'r ddyfais NVMe;
- y ddyfais rithwir bcache y mae'r rhaglen yn rhedeg ag ef.
Gwyddom fod trosglwyddo ceisiadau yn araf, ond ar gyfer pa rai o'r dyfeisiau hyn? Byddwn yn delio Γ’ hyn ychydig yn ddiweddarach.
Gwyddom yn awr fod digwyddiadau yn debygol o achosi problemau. Nid yw dod o hyd i beth yn union sy'n achosi eu cenhedlaeth mor hawdd. Gadewch i ni dybio bod hwn yn rhyw fath o feddalwedd sy'n cael ei lansio o bryd i'w gilydd. Gawn ni weld pa fath o feddalwedd sy'n rhedeg ar y system gan ddefnyddio sgript execsnoop o'r un
Er enghraifft fel hyn:
/usr/share/bcc/tools/execsnoop | tee ./execdump
Ni fyddwn yn dangos allbwn llawn execsnoop yma, ond roedd un llinell o ddiddordeb i ni yn edrych fel hyn:
sh 1764905 5802 0 sudo arcconf getconfig 1 AD | grep Temperature | awk -F '[:/]' '{print $2}' | sed 's/^ ([0-9]*) C.*/1/'
Y drydedd golofn yw PPID (pID rhiant) y broses. Trodd y broses gyda PID 5802 yn un o edafedd ein system fonitro. Wrth wirio cyfluniad y system fonitro, canfuwyd paramedrau gwallus. Cymerwyd tymheredd yr addasydd HBA bob 30 eiliad, sy'n llawer amlach na'r angen. Ar Γ΄l newid yr egwyl siec i un hirach, canfuom nad oedd yr hwyrni prosesu ceisiadau ar y gwesteiwr hwn bellach yn sefyll allan o'i gymharu Γ’ gwesteiwyr eraill.
Ond mae'n dal yn aneglur pam roedd y ddyfais bcache mor araf. Fe wnaethom baratoi platfform prawf gyda chyfluniad union yr un fath a cheisio atgynhyrchu'r broblem trwy redeg fio on bcache, gan redeg sbardun udevadm o bryd i'w gilydd i gynhyrchu uevents.
Ysgrifennu Offer yn Seiliedig ar BCC
Gadewch i ni geisio ysgrifennu cyfleustodau syml i olrhain ac arddangos y galwadau arafaf cais_gwneud_generig(). Mae gennym ddiddordeb hefyd yn enw'r gyriant y galwyd y swyddogaeth hon ar ei gyfer.
Mae'r cynllun yn syml:
- Cofrestrwch kprobe ar cais_gwneud_generig():
- Rydym yn cadw enw'r ddisg yn y cof, sy'n hygyrch trwy'r ddadl swyddogaeth;
- Rydym yn arbed y stamp amser.
- Cofrestrwch kretprobe am ddychwelyd o cais_gwneud_generig():
- Cawn y stamp amser presennol;
- Edrychwn am y stamp amser a arbedwyd a'i gymharu Γ’'r un gyfredol;
- Os yw'r canlyniad yn fwy na'r un penodedig, yna rydym yn dod o hyd i enw'r ddisg sydd wedi'i gadw a'i arddangos ar y derfynell.
Kprobes ΠΈ kretprobes defnyddio mecanwaith torbwynt i newid cod swyddogaeth ar y hedfan. Gallwch ddarllen
Mae'r testun eBPF y tu mewn i'r sgript python yn edrych fel hyn:
bpf_text = βββ # Here will be the bpf program code βββ
I gyfnewid data rhwng swyddogaethau, mae rhaglenni eBPF yn defnyddio
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);
Yma rydym yn cofrestru tabl hash o'r enw p, gyda math allweddol u64 a gwerth o fath strwythuro data_t. Bydd y tabl ar gael yng nghyd-destun ein rhaglen BPF. Mae'r macro BPF_PERF_OUTPUT yn cofrestru tabl arall o'r enw digwyddiadau, a ddefnyddir ar gyfer
Wrth fesur oedi rhwng galw swyddogaeth a dychwelyd ohoni, neu rhwng galwadau i wahanol swyddogaethau, mae angen i chi ystyried bod yn rhaid i'r data a dderbynnir berthyn i'r un cyd-destun. Mewn geiriau eraill, mae angen i chi gofio am lansiad cyfochrog posibl o swyddogaethau. Mae gennym y gallu i fesur yr hwyrni rhwng galw swyddogaeth yng nghyd-destun un broses a dychwelyd oβr swyddogaeth honno yng nghyd-destun proses arall, ond mae hyn yn debygol o fod yn ddiwerth. Enghraifft dda yma fyddai
Nesaf, mae angen i ni ysgrifennu'r cod a fydd yn rhedeg pan fydd y swyddogaeth dan sylw yn cael ei alw:
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);
}
Yma bydd dadl gyntaf y ffwythiant a elwir yn cael ei disodli fel yr ail ddadl
Bydd y swyddogaeth ganlynol yn cael ei galw wrth ddychwelyd o cais_gwneud_generig():
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);
}
}
Mae'r swyddogaeth hon yn debyg i'r un blaenorol: rydym yn darganfod PID y broses a'r stamp amser, ond nid ydym yn dyrannu cof ar gyfer y strwythur data newydd. Yn lle hynny, rydym yn chwilio'r tabl hash am strwythur sydd eisoes yn bodoli gan ddefnyddio'r allwedd == PID cyfredol. Os canfyddir y strwythur, yna byddwn yn darganfod enw'r broses redeg ac yn ei ychwanegu ato.
Mae angen y shifft deuaidd rydyn ni'n ei ddefnyddio yma i gael yr edefyn GID. y rhai. PID o'r brif broses a ddechreuodd yr edefyn yn y cyd-destun yr ydym yn gweithio arno. Y swyddogaeth rydyn ni'n ei galw
Wrth allbynnu i'r derfynell, nid oes gennym ddiddordeb yn yr edefyn ar hyn o bryd, ond mae gennym ddiddordeb yn y brif broses. Ar Γ΄l cymharu'r oedi canlyniadol Γ’ throthwy penodol, rydym yn pasio ein strwythur data i mewn i ofod defnyddiwr trwy fwrdd digwyddiadau, ac ar Γ΄l hynny rydym yn dileu'r cofnod o p.
Yn y sgript python a fydd yn llwytho'r cod hwn, mae angen i ni ddisodli MIN_US a FACTOR gyda'r trothwyon oedi a'r unedau amser, y byddwn yn mynd trwy'r dadleuon:
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"
Nawr mae angen i ni baratoi'r rhaglen BPF trwy
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")
Bydd yn rhaid inni benderfynu hefyd strwythuro data_t yn ein sgript, fel arall ni fyddwn yn gallu darllen unrhyw beth:
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)]
Y cam olaf yw allbynnu data i'r derfynell:
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()
Mae'r sgript ei hun ar gael yn
O'r diwedd! Nawr rydym yn gweld bod yr hyn sy'n edrych fel dyfais bcache arafu mewn gwirionedd yn alwad stopio cais_gwneud_generig() ar gyfer disg wedi'i storio.
Cloddio i mewn i'r Cnewyllyn
Beth yn union sy'n arafu wrth drosglwyddo cais? Gwelwn fod yr oedi yn digwydd hyd yn oed cyn dechrau cyfrifo ceisiadau, h.y. nid yw cyfrifo cais penodol am allbwn pellach o ystadegau arno (/proc/diskstats neu iostat) wedi dechrau eto. Gellir gwirio hyn yn hawdd trwy redeg iostat wrth atgynhyrchu'r broblem, neu
Os edrychwn ar y swyddogaeth cais_gwneud_generig(), yna byddwn yn gweld, cyn i'r cais ddechrau cyfrifo, gelwir dwy swyddogaeth arall. Yn gyntaf - gwiriadau_gwneud_cais_generig(), yn perfformio gwiriadau ar gyfreithlondeb y cais o ran gosodiadau'r ddisg. Ail -
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));
Ynddo, mae'r cnewyllyn yn aros i'r ciw ddadrewi. Gadewch i ni fesur yr oedi blk_ciw_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 | |
Mae'n edrych fel ein bod ni'n agos at ateb. Y swyddogaethau a ddefnyddir i rewi/dadrewi ciw yw
Mae'r amser mae'n ei gymryd i glirio'r ciw hwn yn cyfateb i hwyrni disg gan fod y cnewyllyn yn aros i'r holl weithrediadau ciwio gael eu cwblhau. Unwaith y bydd y ciw yn wag, caiff y newidiadau gosodiadau eu cymhwyso. Wedi hynny fe'i gelwir
Nawr rydyn ni'n gwybod digon i unioni'r sefyllfa. Mae'r gorchymyn sbarduno udevadm yn achosi'r gosodiadau ar gyfer y ddyfais bloc i'w gymhwyso. Disgrifir y gosodiadau hyn yn y rheolau udev. Gallwn ddarganfod pa osodiadau sy'n rhewi'r ciw trwy geisio eu newid trwy sysfs neu trwy edrych ar y cod ffynhonnell cnewyllyn. Gallwn hefyd roi cynnig ar y cyfleustodau 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]
Anaml iawn y mae rheolau Udev yn newid ac fel arfer mae hyn yn digwydd mewn modd rheoledig. Felly gwelwn fod hyd yn oed cymhwyso'r gwerthoedd a osodwyd eisoes yn achosi cynnydd sydyn yn yr oedi wrth drosglwyddo'r cais o'r cais i'r ddisg. Wrth gwrs, nid yw cynhyrchu digwyddiadau udev pan nad oes unrhyw newidiadau yng nghyfluniad y ddisg (er enghraifft, nid yw'r ddyfais wedi'i gosod / datgysylltu) yn arfer da. Fodd bynnag, gallwn helpu'r cnewyllyn i beidio Γ’ gwneud gwaith diangen a rhewi'r ciw cais os nad oes angen.
Casgliad
Mae eBPF yn offeryn hyblyg a phwerus iawn. Yn yr erthygl fe wnaethom edrych ar un achos ymarferol a dangos rhan fach o'r hyn y gellir ei wneud. Os oes gennych ddiddordeb mewn datblygu cyfleustodau BCC, mae'n werth edrych arno
Mae yna offer dadfygio a phroffilio diddorol eraill yn seiliedig ar eBPF. Un o nhw -
Ffynhonnell: hab.com