看看你的Go應(yīng)用是否用了正確CPU核數(shù)
Go 的調(diào)度模型
Go 的調(diào)度模型是 GMP,其中 G 是 goroutine,M 是線程,P 是可用的 CPU 核數(shù)。多個(gè) G 會共用一個(gè) M。M 作為操作系統(tǒng)層面上的調(diào)度單位,在執(zhí)行時(shí)需要綁定到 P。如果操作系統(tǒng)認(rèn)為的某個(gè) Go 進(jìn)程可用的 CPU 數(shù),和該進(jìn)程認(rèn)為的可用的 CPU 數(shù)不一致,那么即使把 M 綁定到某個(gè) P 上,操作系統(tǒng)也不一定會執(zhí)行這個(gè)線程。所以能否獲取準(zhǔn)確的可用 CPU 核數(shù)會影響 Go 的調(diào)度效率。
k8s 設(shè)置資源限制
當(dāng)用戶在 k8s 中設(shè)置了資源限制:
spec:
containers:
- name: app_written_by_go
resources:
limits:
cpu: "4"Go 會不會識別到可用的 CPU 為 4 呢?讀者可能會認(rèn)為,Go 作為一個(gè)云原生時(shí)代炙手可熱的語言,應(yīng)該內(nèi)置了對 k8s 的支持,所以能夠識別出來。但事實(shí)并非如此。
小實(shí)驗(yàn)
如果啟動 Go 進(jìn)程時(shí)沒有指定 GOMAXPROCS 環(huán)境變量,那么會以 runtime.NumCPU() 的輸出作為可用的 CPU 核數(shù)(也即 P 的值)。讓我們加一下打印 NumCPU 的代碼,會發(fā)現(xiàn)實(shí)際上輸出的是 Node 上的 CPU 數(shù)目,跟 limits.cpu 無關(guān)。
runtime.NumCPU() 在 Linux 上是通過系統(tǒng)調(diào)用 sched_getaffinity 實(shí)現(xiàn)的,但這個(gè)系統(tǒng)調(diào)用只考慮綁定 CPU 核的情況,不涉及容器環(huán)境下 cgroup 對 CPU 資源的限制。以 docker 為例,docker run 時(shí)指定 --cpuset-cpus 可以設(shè)置容器運(yùn)行時(shí)可以使用的 CPU 核的編號,但限制 CPU 的資源數(shù)主要用 --cpus=。只有前者(cpuset)是能被 sched_getaffinity 識別的。
具體見 https://docs.docker.com/config/containers/resource_constraint...。如果要想計(jì)算后者,那么需要讀取機(jī)器上的 cgroup fs 文件。
有一個(gè) Go 庫支持讀取 cgroup fs 并計(jì)算出準(zhǔn)確的 GOMAXPROCS:
https://github.com/uber-go/automaxprocs它支持兩種不同的 cgroup fs (cgroup v1 和 v2):
其中 v1 是讀取文件 cpu.cfs_quota_us 和 cpu.cfs_period_us,并求兩者的商。這兩個(gè)文件通常位于 /sys/fs/cgroup/cpu/ 下面(automaxprocs 會讀掛載信息來獲取實(shí)際位置)。
v2 則是讀取文件 cpu.max 里面對應(yīng)表示 quota 和 period 的字段,并求兩者的商。除法的結(jié)果不一定是整數(shù),所以還有一個(gè)向下取整的過程。
存在“應(yīng)該能夠識別可用 CPU 數(shù)但在容器環(huán)境下實(shí)際辦不到”這種問題的并不只有 Go 一個(gè)。Nginx / Envoy 也有無法識別 cgroup 配置的問題。據(jù)說 Rust 和 Java (OpenJDK 實(shí)現(xiàn))有專門處理過 cgroup 配置。如果你的應(yīng)用符合下面兩點(diǎn):
- 計(jì)算密集型或主要業(yè)務(wù)邏輯在若干個(gè)固定的 worker 中完成
- 會部署到容器環(huán)境中
那么不妨看看所用的框架是否能正確處理 cgroup 配置。
附注:IBM 的員工曾經(jīng)提過一個(gè) CPU Namespace 的設(shè)計(jì),封裝每個(gè)進(jìn)程可以看得到的 CPU 信息,避免諸如 CPU 分配不一致這樣的“抽象泄漏”。不過后續(xù)就沒有下文了。
以上就是看看你的Go應(yīng)用真的用了正確的CPU核數(shù)嗎的詳細(xì)內(nèi)容,更多關(guān)于Go應(yīng)用CPU核數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go基于GORM 獲取當(dāng)前請求所執(zhí)行的 SQL 信息(思路詳解)
這篇文章主要介紹了Go基于GORM 獲取當(dāng)前請求所執(zhí)行的 SQL 信息(思路詳解),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例
這篇文章主要為大家介紹了go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究
這篇文章主要為大家介紹了Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
關(guān)于Golang中for-loop與goroutine的問題詳解
這篇文章主要給大家介紹了關(guān)于Golang中for-loop與goroutine問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09

