大家好,我是飞哥!
给大家分享一个事情。背景是这样的,我们要测试某个第三方 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 就能搞定。
代码语言:javascript复制# cd /sys/fs/cgroup/cpu,cpuacct
# mkdir test
# cd test
这时候 cgroup 已经在 test 这个目录下帮我们创建好了一些文件,通过修改这些文件可以控制进程的 CPU 消耗的。
代码语言:javascript复制# 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 个核,那么就这样。
代码语言:javascript复制# 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 限制中。
代码语言:javascript复制# echo $$
16403
sh -c "echo 16403 > cgroup.procs"
这个时候我们使用一个简单的工具 ,stress。用它来模拟开篇 sdk 的 cpu 密集型工作。通过 -c 指定开启几个进程,然后每个进程都反复不停的计算随机数的平方根,尽最大努力消耗 cpu。
代码语言:javascript复制# stress -c 4
另外启动一个控制台,观察 cpu 消耗。发现总量确实是控制住了。stress 及其子进程加起来都只使用了 1 核。
不过我发现了一个不满意的地方。虽然 cpu 用量是控制住了,但是 cpu 消耗是分散在各个 cpu 核上的,而且还是飘来飘去的。我想要的效果是限制它在某一个核上运行。
回来查看了一下 cgroup 目录下的文件。猛然看到了一个叫 cpuset 的 group。第六感告诉我,它一定可以!
代码语言:javascript复制# 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 压力。
代码语言:javascript复制# stress -c 4
在另外一个控制台上查看效果。
完美!这次不但将 cpu 用量控制在了一个核,而且也将 CPU 消耗牢牢地钉在了 cpu0 上。这就是我想要的效果!
基于这个方法,我们就非常准确地完成了对那个第三方 sdk 的 cpu 消耗用量的测试。也评估出来未来上线后需要几台服务器。