給大家分享一個事情。背景是這樣的,我們要測試某個第三方 SDK 執行效能,這是個 CPU 密集型的服務。我想評估一下它執行一遍到底有多吃 CPU,以便評估上線後我們需要部署多少臺伺服器。
我們是在一臺 16 物理核的機器上測試的,我們的想法是把它啟動起來,然後執行一遍。用耗時乘以 16 核那就是總的 CPU 耗時開銷。不過不巧的是我們發現這個貨在併發上做的並不是特別好,執行的前半段裡只能打滿一個核,而後半段可以把整臺機器上所有 16 核都打滿。這樣就沒法準確估算它的 CPU 消耗了。
最先我想到的方案是將這個 SDK 進行 numa 繫結。但是 nuam 繫結只能將 cpu 限制在一個 node 上,我的機器上 一個 node 裡有 8 個核。問題仍然存在,還是不能精確控制 cpu 的用量。
所以我接著又想到了 cgroup 。假如我能從始至終都限制這個 SDK 只使用一個核,且把一個核全部打滿,這樣我就能準確地評估它的 CPU 耗時。
說幹就幹。Cgroup 這玩意兒聽起來複雜,沒想到用起來那是超級的簡單。首先我找到了 cpu,cpuacct 這個 group。在它下面建立一個子 group,一行 mkdir 就能搞定。
# cd /sys/fs/cgroup/cpu,cpuacct
# mkdir test
# cd test
這時候 cgroup 已經在 test 這個目錄下幫我們建立好了一些檔案,透過修改這些檔案可以控制程序的 CPU 消耗的。
# ls -l
total 0
-rw-r--r-- 1 root root 0 Sep 23 11:38 cgroup.procs
-rw-r--r-- 1 root root 0 Sep 23 11:37 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Sep 23 11:37 cpu.cfs_quota_us
......
為了簡便,我們只關注上面幾個檔案。其中 cfs_period_us 用來配置時間週期長度,cfs_quota_us 用來配置當前 cgroup 在設定的週期長度內所能使用的 CPU 時間。這兩個檔案配合起來就可以設定 CPU 的使用上限。
比如我想控制我的程序最多隻能使用 1 個核,那麼就這樣。
# echo 500000 > cpu.cfs_quota_us // 500ms
# echo 500000 > cpu.cfs_period_us // 500ms
每 500ms 能使用 500ms的 CPU 時間,即將 cpu 使用限制在 1 個核以內。(如果想要限制只用兩個核,那就把 cpu.cfs_quota_us 改成 1000000 即可)
這個時候,還缺關鍵的一步。把要限制的程序加進來。這個也簡單,修改 cgroup.procs 把要限制的程序 pid 新增進去就行了。
這裡有個細節,那就是加入一個程序後,這個程序建立的子程序都將預設加到這個 cgroup 的限制中。雖然我們不知道我們將要啟動的程序的 pid 是多少,但是我們可以查到當前 bash 程序的 pid,只要把它加進來就行了。這樣後面透過控制檯啟動程序的時候,都將自動進入 cgroup 限制中。
# echo $$
16403
sh -c "echo 16403 > cgroup.procs"
這個時候我們使用一個簡單的工具 ,stress。用它來模擬開篇 sdk 的 cpu 密集型工作。透過 -c 指定開啟幾個程序,然後每個程序都反覆不停的計算隨機數的平方根,盡最大努力消耗 cpu。
# stress -c 4
另外啟動一個控制檯,觀察 cpu 消耗。發現總量確實是控制住了。stress 及其子程序加起來都只使用了 1 核。
不過我發現了一個不滿意的地方。雖然 cpu 用量是控制住了,但是 cpu 消耗是分散在各個 cpu 核上的,而且還是飄來飄去的。我想要的效果是限制它在某一個核上執行。
回來查看了一下 cgroup 目錄下的檔案。猛然看到了一個叫 cpuset 的 group。第六感告訴我,它一定可以!
# ll /sys/fs/cgroup/
total 0
drwxr-xr-x 2 root root 0 Sep 15 17:43 blkio
lrwxrwxrwx 1 root root 11 Sep 15 17:43 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Sep 15 17:43 cpuacct -> cpu,cpuacct
drwxr-xr-x 4 root root 0 Sep 15 17:43 cpu,cpuacct
drwxr-xr-x 3 root root 0 Sep 15 17:43 cpuset // 就是它!
......
於是乎,我先是廢棄了剛剛的 test 配置,直接刪除即可(rm -rf /sys/fs/cgroup/cpu,cpuacct)。再搜了一下這個 cpuset 怎麼用,開始新的配置。
# cd /sys/fs/cgroup/cpuset
# mkdir test && cd test
# echo "0" > cpuset.cpus //限制在第 0 號核上
# echo 0 > cpuset.mems
# echo $$ > cgroup.procs
繼續開始施加 cpu 壓力。
# stress -c 4
在另外一個控制檯上檢視效果。
完美!這次不但將 cpu 用量控制在了一個核,而且也將 CPU 消耗牢牢地釘在了 cpu0 上。這就是我想要的效果!
基於這個方法,我們就非常準確地完成了對那個第三方 sdk 的 cpu 消耗用量的測試。也評估出來未來上線後需要幾臺伺服器。