iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0
Cloud Native

30 篇文帶你用 eBPF 與 Golang 打造 Linux Scheduler系列 第 18

scx_goland_core 移植與挑戰(三):data unsync

  • 分享至 

  • xImage
  •  

如果覺得文章對你有所啟發,可以考慮用 🌟 支持 Gthulhu 專案,短期目標是集齊 300 個 🌟 藉此被 CNCF Landscape 採納 [ref]

克服了前面兩個巨大的挑戰後,基本上 Gthulhu 就已經有一定的穩定性了(至少在我的主力開發機器上熬過了漫長的 7x24 Hrs)。但是,還是有一個問題非常困擾我。

基本上,eBPF program 的全域變數會根據不同的宣告方式被歸類在不同的 segment:

	struct {
		struct bpf_map *cpu_ctx_stor;
		struct bpf_map *task_ctx_stor;
		struct bpf_map *queued;
		struct bpf_map *dispatched;
		struct bpf_map *priority_tasks;
		struct bpf_map *running_task;
		struct bpf_map *usersched_timer;
		struct bpf_map *rodata;
		struct bpf_map *data_uei_dump;
		struct bpf_map *data;
		struct bpf_map *bss;
		struct bpf_map *goland;
	} maps;

上方程式碼是由 bpftool 產生的 skeleton file 的一部分,可以發現 Gthulhu 使用的 eBPF program 就至少會有:

  • bss
  • data
  • rodata

其中,bss 存放的資料非常重要:

	struct main_bpf__bss {
		u64 usersched_last_run_at;
		u64 nr_queued;
		u64 nr_scheduled;
		u64 nr_running;
		u64 nr_online_cpus;
		u64 nr_user_dispatches;
		u64 nr_kernel_dispatches;
		u64 nr_cancel_dispatches;
		u64 nr_bounce_dispatches;
		u64 nr_failed_dispatches;
		u64 nr_sched_congested;
	} *bss;

這裡面的 nr_scheduled 以及 nr_queued 會影響 user space scheduler 為一個任務分配 time slice 的大小(呼應前面說的,scx_rustland 會根據待排程任務的數量決定 time slice)。

然而,libbpfgo 的 API 會將一個 bss section 視為一個 eBPF MAP,如果我今天先讀取後更新這份 MAP,在這個期間 eBPF program 只要對這個 MAP 裡面的資料增減,就會造成 DATA RACE 的問題。這類的問題如果出現在 DATABASE,就有點像是買超賣超的問題,不過在 DATABASE 的場景中使用 transaction 或是 DB Lock 就能解決這個問題了。

scx_rustland 本身會直接呼叫 skeleton API,所以能夠指定更新 bss map 的某一個欄位,為了克服這個惱人的問題,我的解法就是利用 eBPF skeleton

// wrapper.c
#include "wrapper.h"

struct main_bpf *global_obj;

void *open_skel() {
    struct main_bpf *obj = NULL;
    obj = main_bpf__open();
    main_bpf__create_skeleton(obj);
    global_obj = obj;
    return obj->obj;
}

u32 get_usersched_pid() {
    return global_obj->rodata->usersched_pid;
}

void set_usersched_pid(u32 id) {
    global_obj->rodata->usersched_pid = id;
}

void set_kugepagepid(u32 id) {
    global_obj->rodata->khugepaged_pid = id;
}

void set_early_processing(bool enabled) {
    global_obj->rodata->early_processing = enabled;
}

void set_default_slice(u64 t) {
    global_obj->rodata->default_slice = t;
}

void set_debug(bool enabled) {
    global_obj->rodata->debug = enabled;
}

void set_builtin_idle(bool enabled) {
    global_obj->rodata->builtin_idle = enabled;
}

u64 get_nr_scheduled() {
    return global_obj->bss->nr_scheduled;
}

u64 get_nr_queued() {
    return global_obj->bss->nr_queued;
}

void notify_complete(u64 nr_pending) {
    global_obj->bss->nr_scheduled = nr_pending;
}

void sub_nr_queued() {
    if (global_obj->bss->nr_queued){
        global_obj->bss->nr_queued--;
    }
}

void destroy_skel(void*skel) {
    main_bpf__destroy(skel);
}

golang 雖然無法像 rust 一樣直接使用 skeleton API,但我可以將這些 API 進行封裝,再利用 cgo 呼叫這些函式。

wrapper:
	bpftool gen skeleton main.bpf.o > main.skeleton.h
	clang -g -O2 -Wall -fPIC -I scx/build/libbpf/src/usr/include -I scx/build/libbpf/include/uapi -I scx/scheds/include -I scx/scheds/include/arch/x86 -I scx/scheds/include/bpf-compat -I scx/scheds/include/lib -c wrapper.c -o wrapper.o
	ar rcs libwrapper.a wrapper.o

透過上面的方式,將 wrapper 變成靜態鏈結函式庫,供 Gthulhu 使用:

CGOFLAG = CC=clang CGO_CFLAGS="-I$(BASEDIR) -I$(BASEDIR)/$(OUTPUT)" CGO_LDFLAGS="-lelf -lz $(LIBBPF_OBJ) -lzstd $(BASEDIR)/libwrapper.a"

如此一來,就能夠在 golang 呼叫這些封裝過的 API 了:

func (s *Sched) AssignUserSchedPid(pid int) error {
	C.set_kugepagepid(C.u32(KhugepagePid()))
	C.set_usersched_pid(C.u32(pid))
	return nil
}

func (s *Sched) SetDebug(enabled bool) {
	C.set_debug(C.bool(enabled))
}

func (s *Sched) SetBuiltinIdle(enabled bool) {
	C.set_builtin_idle(C.bool(enabled))
}

func (s *Sched) SetEarlyProcessing(enabled bool) {
	C.set_early_processing(C.bool(enabled))
}

func (s *Sched) SetDefaultSlice(t uint64) {
	C.set_default_slice(C.u64(t))
}

總結

截至目前為止,我們已經探討了將 scx_rustland 重新以 golang 實作時會遇到的“大問題”,接下來就可以將我多年泡在 free5GC 學到的奇怪知識與想法結合 Gthulhu,打造一款面向雲原生應用的排程器方案了👍


上一篇
scx_goland_core 移植與挑戰(二):watchdog failed to check in for default timeout
下一篇
Gthulhu 系統設計
系列文
30 篇文帶你用 eBPF 與 Golang 打造 Linux Scheduler21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言