看看你的Go應(yīng)用是否用了正確CPU核數(shù)
Go 的調(diào)度模型
Go 的調(diào)度模型是 GMP,其中 G 是 goroutine,M 是線程,P 是可用的 CPU 核數(shù)。多個(gè) G 會(huì)共用一個(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)也不一定會(huì)執(zhí)行這個(gè)線程。所以能否獲取準(zhǔn)確的可用 CPU 核數(shù)會(huì)影響 Go 的調(diào)度效率。
k8s 設(shè)置資源限制
當(dāng)用戶在 k8s 中設(shè)置了資源限制:
spec:
containers:
- name: app_written_by_go
resources:
limits:
cpu: "4"Go 會(huì)不會(huì)識(shí)別到可用的 CPU 為 4 呢?讀者可能會(huì)認(rèn)為,Go 作為一個(gè)云原生時(shí)代炙手可熱的語言,應(yīng)該內(nèi)置了對(duì) k8s 的支持,所以能夠識(shí)別出來。但事實(shí)并非如此。
小實(shí)驗(yàn)
如果啟動(dòng) Go 進(jìn)程時(shí)沒有指定 GOMAXPROCS 環(huán)境變量,那么會(huì)以 runtime.NumCPU() 的輸出作為可用的 CPU 核數(shù)(也即 P 的值)。讓我們加一下打印 NumCPU 的代碼,會(huì)發(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 對(duì) CPU 資源的限制。以 docker 為例,docker run 時(shí)指定 --cpuset-cpus 可以設(shè)置容器運(yùn)行時(shí)可以使用的 CPU 核的編號(hào),但限制 CPU 的資源數(shù)主要用 --cpus=。只有前者(cpuset)是能被 sched_getaffinity 識(shí)別的。
具體見 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 會(huì)讀掛載信息來獲取實(shí)際位置)。
v2 則是讀取文件 cpu.max 里面對(duì)應(yīng)表示 quota 和 period 的字段,并求兩者的商。除法的結(jié)果不一定是整數(shù),所以還有一個(gè)向下取整的過程。
存在“應(yīng)該能夠識(shí)別可用 CPU 數(shù)但在容器環(huán)境下實(shí)際辦不到”這種問題的并不只有 Go 一個(gè)。Nginx / Envoy 也有無法識(shí)別 cgroup 配置的問題。據(jù)說 Rust 和 Java (OpenJDK 實(shí)現(xiàn))有專門處理過 cgroup 配置。如果你的應(yīng)用符合下面兩點(diǎn):
- 計(jì)算密集型或主要業(yè)務(wù)邏輯在若干個(gè)固定的 worker 中完成
- 會(huì)部署到容器環(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ù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的步驟
目前,OpenCV逐步成為一個(gè)通用的基礎(chǔ)研究和產(chǎn)品開發(fā)平臺(tái),下面這篇文章主要給大家介紹了關(guān)于利用golang進(jìn)行OpenCV學(xué)習(xí)和開發(fā)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-09-09
golang?metrics各個(gè)指標(biāo)含義講解說明
這篇文章主要為大家介紹了golang?metrics各個(gè)指標(biāo)含義講解說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
Golang使用DuckDB查詢Parquet文件數(shù)據(jù)的操作代碼
本文介紹DuckDB查詢Parquet文件的典型應(yīng)用場景,掌握DuckDB會(huì)讓你的產(chǎn)品分析能力更強(qiáng),相反系統(tǒng)運(yùn)營成本相對(duì)較低,為了示例完整,我也提供了如何使用Python導(dǎo)出MongoDB數(shù)據(jù),需要的朋友可以參考下2025-01-01
golang中struct和[]byte的相互轉(zhuǎn)換示例
這篇文章主要介紹了golang中struct和[]byte的相互轉(zhuǎn)換示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07
Go語言實(shí)現(xiàn)圖片快遞信息識(shí)別的簡易方法
這篇文章主要為大家介紹了Go語言實(shí)現(xiàn)圖片快遞信息識(shí)別的簡易方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10

