ඉහළ Ceph Latency සිට eBPF/BCC භාවිතයෙන් කර්නල් පැච් දක්වා

ඉහළ Ceph Latency සිට eBPF/BCC භාවිතයෙන් කර්නල් පැච් දක්වා

Linux සතුව කර්නලය සහ යෙදුම් නිදොස් කිරීම සඳහා මෙවලම් විශාල ප්‍රමාණයක් ඇත. ඒවායින් බොහොමයක් යෙදුම් කාර්ය සාධනය කෙරෙහි ඍණාත්මක බලපෑමක් ඇති කරන අතර නිෂ්පාදනයේදී භාවිතා කළ නොහැක.

අවුරුදු කීපයකට කලින් තිබුණා තවත් මෙවලමක් සංවර්ධනය කර ඇත - eBPF. එය කර්නලය සහ පරිශීලක යෙදුම් අඩු පොදු කාර්යක් සහිතව සහ වැඩසටහන් නැවත ගොඩ නැගීම සහ කර්නලයට තෙවන පාර්ශවීය මොඩියුල පැටවීමේ අවශ්‍යතාවයකින් තොරව සොයා ගැනීමට හැකි වේ.

eBPF භාවිතා කරන බොහෝ යෙදුම් උපයෝගිතා දැනටමත් ඇති අතර, මෙම ලිපියෙන් අපි පුස්තකාලය මත පදනම්ව ඔබේම පැතිකඩ උපයෝගීතාවයක් ලියන්නේ කෙසේදැයි බලමු. PythonBCC. ලිපිය සත්‍ය සිදුවීම් මත පදනම් වේ. විශේෂිත අවස්ථාවන්හිදී පවතින උපයෝගිතා භාවිතා කළ හැකි ආකාරය පෙන්වීමට අපි ගැටලුවෙන් විසඳීමට යන්නෙමු.

Ceph මන්දගාමී වේ

Ceph පොකුරට නව සත්කාරකයක් එක් කර ඇත. සමහර දත්ත එයට සංක්‍රමණය කිරීමෙන් පසුව, එය මඟින් ලිවීමේ ඉල්ලීම් සැකසීමේ වේගය අනෙකුත් සේවාදායකයන්ට වඩා බෙහෙවින් අඩු බව අපි දුටුවෙමු.

ඉහළ Ceph Latency සිට eBPF/BCC භාවිතයෙන් කර්නල් පැච් දක්වා
අනෙකුත් වේදිකා මෙන් නොව, මෙම ධාරකය bcache සහ නව linux 4.15 කර්නලය භාවිතා කළේය. මෙම වින්‍යාසයේ ධාරකයක් මෙහි භාවිතා කළ පළමු අවස්ථාව මෙය විය. ගැටලුවේ මූලය න්‍යායාත්මකව ඕනෑම දෙයක් විය හැකි බව ඒ මොහොතේ පැහැදිලි විය.

සත්කාරක සමාගම විමර්ශනය කිරීම

අපි පටන් ගනිමු ceph-osd ක්‍රියාවලිය ඇතුලේ මොකද වෙන්නේ කියලා. මේ සඳහා අපි භාවිතා කරන්නෙමු පරිපූර්ණ и ෆ්ලේම්ස්කෝප් (ඔබට කියවිය හැකි වැඩි විස්තර මෙහි):

ඉහළ Ceph Latency සිට eBPF/BCC භාවිතයෙන් කර්නල් පැච් දක්වා
පින්තූරය අපට පවසන්නේ කාර්යය බවයි fdatasync() කාර්යයන් සඳහා ඉල්ලීමක් යැවීමට බොහෝ කාලයක් ගත විය Generic_make_request(). මෙයින් අදහස් කරන්නේ බොහෝ විට ගැටළු වලට හේතුව osd ඩීමන් වලින් පිටත කොහේ හරි බවයි. මෙය කර්නලය හෝ තැටි විය හැක. iostat ප්‍රතිදානය bcache තැටි මඟින් ඉල්ලීම් සැකසීමේ ඉහළ ප්‍රමාදයක් පෙන්නුම් කරයි.

ධාරකය පරීක්ෂා කිරීමේදී, systemd-udevd ඩීමන් CPU කාලය විශාල ප්‍රමාණයක් පරිභෝජනය කරන බව අපට පෙනී ගියේය - මධ්‍ය කිහිපයක 20% පමණ. මෙය අමුතු හැසිරීමකි, එබැවින් ඔබ එයට හේතුව සොයා බැලිය යුතුය. Systemd-udevd uevents සමඟ ක්‍රියා කරන බැවින්, අපි ඒවා හරහා බැලීමට තීරණය කළෙමු udevadm මොනිටරය. පද්ධතියේ එක් එක් බ්ලොක් උපාංගය සඳහා විශාල වෙනස්කම් සිදුවීම් ජනනය කර ඇති බව පෙනී යයි. මෙය තරමක් අසාමාන්‍ය ය, එබැවින් මෙම සියලු සිදුවීම් උත්පාදනය කරන්නේ කුමක් දැයි බැලීමට අපට සිදුවනු ඇත.

BCC මෙවලම් කට්ටලය භාවිතා කිරීම

අප දැනටමත් සොයාගෙන ඇති පරිදි, කර්නලය (සහ පද්ධති ඇමතුමේ ඇති ceph daemon) බොහෝ කාලයක් ගත කරයි Generic_make_request(). මෙම කාර්යයේ වේගය මැනීමට උත්සාහ කරමු. තුල BCC දැනටමත් අපූරු උපයෝගීතාවයක් තිබේ - funclateency. අපි ප්‍රතිදානයන් අතර තත්පර 1 ක පරතරයක් සමඟ එහි PID මගින් ඩීමන් සොයා ගෙන ප්‍රතිඵලය මිලි තත්පර වලින් ප්‍රතිදානය කරන්නෙමු.

ඉහළ Ceph Latency සිට eBPF/BCC භාවිතයෙන් කර්නල් පැච් දක්වා
මෙම විශේෂාංගය සාමාන්යයෙන් ඉක්මනින් ක්රියා කරයි. එය කරන්නේ උපාංගයේ ධාවක පෝලිමට ඉල්ලීම යැවීමයි.

Bcache ඇත්ත වශයෙන්ම තැටි තුනකින් සමන්විත සංකීර්ණ උපාංගයකි:

  • පිටුබලය උපාංගය (හැඹිලි තැටිය), මෙම නඩුවේ එය මන්දගාමී HDD වේ;
  • හැඹිලි උපාංගය (හැඹිලි තැටිය), මෙන්න මෙය NVMe උපාංගයේ එක් කොටසකි;
  • යෙදුම ධාවනය වන bcache අතථ්‍ය උපාංගය.

ඉල්ලීම් සම්ප්‍රේෂණය මන්දගාමී බව අපි දනිමු, නමුත් මෙම උපාංගවලින් කුමන උපාංග සඳහාද? අපි මේ ගැන ටිකක් පසුව කටයුතු කරමු.

සිදුවීම් නිසා ගැටළු ඇති විය හැකි බව අපි දැන් දනිමු. ඔවුන්ගේ පරම්පරාවට හරියටම හේතුව කුමක්දැයි සොයා ගැනීම එතරම් පහසු නැත. අපි හිතමු මේක කාලෙන් කාලෙට එළිදක්වන මෘදුකාංගයක් කියලා. අපි බලමු ස්ක්‍රිප්ට් එකක් භාවිතයෙන් පද්ධතිය මත ක්‍රියාත්මක වන මෘදුකාංග මොනවාද කියා execsnoop එකම සිට BCC උපයෝගිතා කට්ටලය. අපි ඒක run කරලා output එක file එකකට යවමු.

උදාහරණයක් ලෙස මේ වගේ:

/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 (මාපිය PID) වේ. PID 5802 සමඟ ක්‍රියාවලිය අපගේ අධීක්ෂණ පද්ධතියේ එක් නූල් එකක් බවට පත් විය. අධීක්ෂණ පද්ධතියේ වින්යාසය පරීක්ෂා කිරීමේදී, වැරදි පරාමිතීන් සොයා ගන්නා ලදී. HBA ඇඩප්ටරයේ උෂ්ණත්වය සෑම තත්පර 30 කට වරක් ගන්නා ලදී, එය අවශ්ය ප්රමාණයට වඩා බොහෝ විට සිදු වේ. චෙක්පත් පරතරය දිගු එකකට වෙනස් කිරීමෙන් පසුව, මෙම සත්කාරකයේ ඉල්ලීම් සැකසීමේ ප්‍රමාදය අනෙකුත් ධාරක හා සසඳන විට තවදුරටත් කැපී පෙනෙන්නේ නැති බව අපට පෙනී ගියේය.

නමුත් bcache උපාංගය මෙතරම් මන්දගාමී වූයේ මන්දැයි තවමත් පැහැදිලි නැත. අපි සමාන වින්‍යාසයක් සහිත පරීක්ෂණ වේදිකාවක් සකස් කර, bcache මත fio ධාවනය කිරීමෙන්, uevens උත්පාදනය කිරීමට udevadm ප්‍රේරකය වරින් වර ධාවනය කිරීමෙන් ගැටලුව ප්‍රතිනිෂ්පාදනය කිරීමට උත්සාහ කළෙමු.

BCC-පාදක මෙවලම් ලිවීම

මන්දගාමී ඇමතුම් සොයා ගැනීමට සහ සංදර්ශන කිරීමට සරල උපයෝගීතාවයක් ලිවීමට උත්සාහ කරමු Generic_make_request(). මෙම කාර්යය හැඳින්වූ ධාවකයේ නම ගැනද අපි උනන්දු වෙමු.

සැලැස්ම සරලයි:

  • අපි ලියාපදිංචි වෙනවා kprobe මත Generic_make_request():
    • අපි තැටියේ නම මතකයට සුරකිමු, ක්‍රියාකාරී තර්කය හරහා ප්‍රවේශ විය හැකිය;
    • අපි කාල මුද්‍රාව සුරකිමු.

  • අපි ලියාපදිංචි වෙනවා kretprobe සිට ආපසු පැමිණීම සඳහා Generic_make_request():
    • අපි වත්මන් වේලා මුද්රාව ලබා ගනිමු;
    • අපි සුරකින ලද වේලා මුද්‍රාව සොයන අතර එය වත්මන් එක සමඟ සසඳන්න;
    • ප්‍රති result ලය නියමිත ප්‍රමාණයට වඩා වැඩි නම්, අපි සුරකින ලද තැටි නම සොයාගෙන එය ටර්මිනලයේ ප්‍රදර්ශනය කරමු.

Kprobes и kretprobes පියාසර කරන විට ක්‍රියාකාරී කේතය වෙනස් කිරීමට බ්‍රේක්පොයින්ට් යාන්ත්‍රණයක් භාවිතා කරන්න. ඔබට කියවිය හැකිය ලේඛනගත කිරීම и යහපත මෙම මාතෘකාව පිළිබඳ ලිපිය. ඔබ විවිධ උපයෝගිතා කේතය දෙස බැලුවහොත් BCC, එවිට ඔබට සමාන ව්යුහයක් ඇති බව ඔබට පෙනෙනු ඇත. එබැවින් මෙම ලිපියෙන් අපි ස්ක්‍රිප්ට් තර්ක විග්‍රහ කිරීම මඟ හැර BPF වැඩසටහන වෙතම යමු.

පයිතන් ස්ක්‍රිප්ටය තුළ ඇති ඊබීපීඑෆ් පෙළ මේ ආකාරයට පෙනේ:

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 මැක්‍රෝව තවත් වගුවක් ලියාපදිංචි කරයි සිද්ධීන්, සඳහා භාවිතා කරනු ලැබේ දත්ත සම්ප්රේෂණය පරිශීලක අවකාශයට.

ශ්‍රිතයක් ඇමතීම සහ එයින් ආපසු පැමිණීම අතර හෝ විවිධ කාර්යයන් සඳහා ඇමතුම් අතර ප්‍රමාදයන් මැනීමේදී, ලැබුණු දත්ත එකම සන්දර්භයට අයත් විය යුතු බව ඔබ සැලකිල්ලට ගත යුතුය. වෙනත් වචන වලින් කිවහොත්, කාර්යයන් සමාන්තරව දියත් කිරීම ගැන ඔබ මතක තබා ගත යුතුය. එක් ක්‍රියාවලියක සන්දර්භය තුළ ශ්‍රිතයක් ඇමතීම සහ වෙනත් ක්‍රියාවලියක සන්දර්භය තුළ එම ශ්‍රිතයෙන් නැවත පැමිණීම අතර ප්‍රමාදය මැනීමට අපට හැකියාව ඇත, නමුත් මෙය බොහෝ විට නිෂ්ඵල වේ. මෙහි හොඳ උදාහරණයක් වනු ඇත biolatency උපයෝගීතාව, හෑෂ් වගු යතුර පොයින්ටරයකට සකසා ඇත struct ඉල්ලීම, එක් තැටි ඉල්ලීමක් පිළිබිඹු කරයි.

ඊළඟට, අපි අධ්‍යයනය යටතේ ඇති ශ්‍රිතය හැඳින්වූ විට ක්‍රියාත්මක වන කේතය ලිවිය යුතුය:

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 සහ නැනෝ තත්පර වලින් වත්මන් කාල මුද්‍රාව ලබා ගනිමු. අපි ඒ සියල්ල අලුතින් තෝරාගත් එකක ලියන්නෙමු දත්ත_t දත්ත ව්‍යුහගත කරන්න. අපි තැටියේ නම ව්යුහයෙන් ලබා ගනිමු ජෛව, ඇමතීමෙන් පසු සම්මත වේ Generic_make_request(), සහ එකම ව්යුහය තුළ එය සුරකින්න දත්ත. අවසාන පියවර වන්නේ කලින් සඳහන් කළ හැෂ් වගුවට ඇතුළත් කිරීමක් එකතු කිරීමයි.

වෙතින් ආපසු පැමිණීමේදී පහත ශ්‍රිතය කැඳවනු ලැබේ 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 සහ කාල මුද්‍රාව සොයා ගනිමු, නමුත් නව දත්ත ව්‍යුහය සඳහා මතකය වෙන් නොකරන්න. ඒ වෙනුවට, අපි == වත්මන් PID යතුර භාවිතයෙන් දැනටමත් පවතින ව්‍යුහයක් සඳහා හැෂ් වගුව සොයන්නෙමු. ව්යුහය සොයාගතහොත්, අපි ධාවන ක්රියාවලියේ නම සොයාගෙන එය එකතු කරන්නෙමු.

අපි මෙහි භාවිතා කරන ද්විමය මාරුව නූල් GID ලබා ගැනීමට අවශ්‍ය වේ. එම. අපි වැඩ කරන සන්දර්භය තුළ නූල් ආරම්භ කළ ප්රධාන ක්රියාවලියේ PID. අපි හඳුන්වන කාර්යය bpf_get_current_pid_tgid() නූල් වල GID සහ එහි PID දෙකම තනි 64-bit අගයකින් ලබා දෙයි.

ටර්මිනලයට ප්‍රතිදානය කරන විට, අපි දැනට නූල් ගැන උනන්දු නොවෙමු, නමුත් අපි ප්‍රධාන ක්‍රියාවලිය ගැන උනන්දු වෙමු. ලැබෙන ප්‍රමාදය ලබා දී ඇති එළිපත්ත සමඟ සංසන්දනය කිරීමෙන් පසුව, අපි අපගේ ව්‍යුහය පසු කරමු දත්ත වගුව හරහා පරිශීලක අවකාශයට සිද්ධීන්, ඉන් පසුව අපි ඇතුළත් කිරීම මකා දමමු p.

මෙම කේතය පූරණය කරන පයිතන් ස්ක්‍රිප්ටය තුළ, අපට 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 මොනිටරය ඇමතීමට ඇති පරීක්ෂණ වේදිකාවක් මත එය ධාවනය කිරීමට උත්සාහ කරමු:

ඉහළ Ceph Latency සිට eBPF/BCC භාවිතයෙන් කර්නල් පැච් දක්වා
අවසාන! දැන් අපට පෙනෙන්නේ ඇනහිටින bcache උපාංගයක් මෙන් පෙනෙන්නේ ඇත්ත වශයෙන්ම ඇණහිට ඇති ඇමතුමක් බවයි Generic_make_request() හැඹිලි තැටියක් සඳහා.

කර්නලය හාරා

ඉල්ලීම සම්ප්‍රේෂණය කිරීමේදී මන්දගාමී වීම යනු කුමක්ද? ඉල්ලීම් ගිණුම්කරණය ආරම්භ වීමට පෙර පවා ප්‍රමාදය සිදුවන බව අපට පෙනේ, i.e. එය (/proc/diskstats හෝ iostat) පිළිබඳ සංඛ්‍යාලේඛන තවදුරටත් ප්‍රතිදානය කිරීම සඳහා නිශ්චිත ඉල්ලීමක් ගිණුම්කරණය තවමත් ආරම්භ කර නොමැත. ගැටලුව ප්‍රතිනිෂ්පාදනය කරන අතරතුර iostat ධාවනය කිරීමෙන් මෙය පහසුවෙන් සත්‍යාපනය කළ හැක, හෝ BCC script biolateency, ඉල්ලීම් ගිණුම්කරණයේ ආරම්භය සහ අවසානය මත පදනම් වේ. මෙම උපයෝගිතා කිසිවක් හැඹිලි තැටිය වෙත ඉල්ලීම් සඳහා ගැටළු නොපෙන්වයි.

අපි කාර්යය දෙස බැලුවහොත් Generic_make_request(), එවිට ඉල්ලීම ගිණුම්කරණය ආරම්භ කිරීමට පෙර, තවත් කාර්යයන් දෙකක් කැඳවනු ලබන බව අපට පෙනෙනු ඇත. පලමු - Generic_make_request_checks(), තැටි සැකසුම් සම්බන්ධයෙන් ඉල්ලීමේ නීත්යානුකූල භාවය පිළිබඳ චෙක්පත් සිදු කරයි. දෙවැනි - blk_queue_enter(), සිත්ගන්නා අභියෝගයක් ඇත ඉන්න_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_පෝලිම и blk_mq_unfreeze_පෝලිම. මෙම පෝලිමේ ඉල්ලීම් සඳහා අනතුරුදායක විය හැකි ඉල්ලීම් පෝලිම් සැකසීම් වෙනස් කිරීමට අවශ්‍ය වූ විට ඒවා භාවිත කෙරේ. ඇමතීමේදී blk_mq_freeze_queue() කාර්යය blk_freeze_queue_start() කවුන්ටරය වැඩි කර ඇත q->mq_freeze_depth. මෙයින් පසු, කර්නලය පෝලිම හිස් වන තෙක් බලා සිටී blk_mq_freeze_queue_wait().

මෙම පෝලිම ඉවත් කිරීමට ගතවන කාලය තැටි ප්‍රමාදයට සමාන වේ, මන්ද කර්නලය සියලුම පෝලිම් මෙහෙයුම් සම්පූර්ණ වන තෙක් බලා සිටී. පෝලිම හිස් වූ පසු, සැකසුම් වෙනස් කිරීම් යොදනු ලැබේ. ඉන් පසුව එය හැඳින්වේ blk_mq_unfreeze_queue(), කවුන්ටරය අඩු කිරීම කැටි_ගැඹුර.

දැන් අපි තත්ත්වය නිවැරදි කිරීමට ප්රමාණවත් තරම් දන්නවා. udevadm trigger විධානය මඟින් බ්ලොක් උපාංගයේ සිටුවම් යෙදීමට හේතු වේ. මෙම සැකසුම් udev රීති වල විස්තර කර ඇත. sysfs හරහා ඒවා වෙනස් කිරීමට උත්සාහ කිරීමෙන් හෝ කර්නල් ප්‍රභව කේතය බැලීමෙන් පෝලිම කැටි කරන්නේ කුමන සැකසුම්දැයි අපට සොයාගත හැකිය. අපට BCC උපයෝගීතාව ද උත්සාහ කළ හැකිය ගවේෂණයකි, එය පර්යන්තය වෙත එක් එක් ඇමතුම සඳහා කර්නලය සහ පරිශීලක අවකාශයේ ස්ටැක් ට්‍රේස් ප්‍රතිදානය කරයි blk_freeze_පෝලිමඋදාහරණයක් ලෙස:

~# /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 සිදුවීම් උත්පාදනය කිරීම (උදාහරණයක් ලෙස, උපාංගය සවිකර හෝ විසන්ධි කර නැත) හොඳ භාවිතයක් නොවේ. කෙසේ වෙතත්, කර්නලය අනවශ්‍ය වැඩ නොකිරීමට සහ අවශ්‍ය නැතිනම් ඉල්ලීම් පෝලිම කැටි කිරීමට අපට උදව් කළ හැකිය. තුනක් කුඩා කැප කරනවා තත්වය නිවැරදි කරන්න.

නිගමනය

eBPF යනු ඉතා නම්‍යශීලී සහ බලවත් මෙවලමකි. ලිපියෙන් අපි එක් ප්‍රායෝගික අවස්ථාවක් දෙස බැලූ අතර කළ හැකි දේවලින් කුඩා කොටසක් නිරූපණය කළෙමු. ඔබ BCC උපයෝගිතා සංවර්ධනය කිරීමට කැමති නම්, එය බැලීම වටී නිල නිබන්ධනය, මූලික කරුණු හොඳින් විස්තර කරයි.

eBPF මත පදනම් වූ වෙනත් රසවත් නිදොස්කරණය සහ පැතිකඩ මෙවලම් තිබේ. ඔවුන්ගෙන් එක් කෙනෙක් - bpftrace, එය ඔබට awk වැනි භාෂාවෙන් ප්‍රබල එක පෙළට සහ කුඩා වැඩසටහන් ලිවීමට ඉඩ සලසයි. තවත් - ebpf_exporter, ඔබට පසුව අලංකාර දෘශ්‍යකරණයන් සහ ඇඟවීම් පවා ලබා ගැනීමේ හැකියාව ඇතිව, ඔබේ ප්‍රොමිතියස් සේවාදායකයට සෘජුවම පහත් මට්ටමේ, ඉහළ-විභේදන ප්‍රමිතික එකතු කිරීමට ඉඩ සලසයි.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න