Open islishude opened 4 years ago
请问博主 Containerd container runtime也会有这个问题吗/
请问博主 Containerd container runtime也会有这个问题吗/
这个肯定是一样的,容器的资源限制都是使用 cgroup,不论是什么 runtime
go方面是希望k8s来解决这个issue吗?没看到有k8s方面的讨论?
看样子是k8s也在等go team ,目前一直丢在backlog 没有处理
Right now we're watching the Go issue to fix this for all go applications in the standard library / runtime. There's recent indication that the Go team plan to make Go aware of this.
— Benjamin Elder (@BenTheElder) May 5, 2023
Go 程序启动时候会根据 CPU 数量设置 GOMAXPROCS,比如下面的程序中在 8 核处理下输出为 8。
当我们使用 Docker 的时候也是如此,不过当我们使用 docker run 的时候同时限制了 CPU 数量,那么程序中会正常显示吗?
不会,比如
docker run --cpus=2 IMAGE
,输出还是宿主机的数量。这样就带来一个问题,如果宿主机是一个配置特别大的机器,同时限制了运行容器的 CPU ,那么就会造成 GOMAXPROCS 过大,程序运行中也会过多生成线程。
线程越多,但是 CPU 很少,这就造成线程调度负担,从而导致程序运行变慢。
所以需要去提前设置 GOMAXPROCS 为准确的值,uber 开源了 uber-go/automaxprocs 库,就很好的解决了这个问题,使用很简单。
重新构造 Docker 镜像,再运行,可以看到这里适配了准确的 CPU 数量后自动打印了数据。
这样就很OK了,另外还有一个可选项 LXCFS。什么是 LXCFS ?docker 资源控制的原理的是使用了 cgroup,可以参考耗子叔的文章具体了解。
程序不能获取 cpu 限制,问题出在 docker 直接挂载 cgroup 信息到容器的
/sys/fs/cgroup
目录下,而 lxcfs 所做的就是让这些信息重新挂载到/proc
目录下。接下来介绍如何使用 lxcfs,首先在机器上安装 lxcfs
然后可以根据
which lxcfs
获取到已经安转到/usr/local/bin/lxcfs
,接着配置 systemd 守护进程第一步,创建lxcfs mount 目录
mkdir -p /var/lib/lxcfs
,接着配置 systemd然后就可以启动lxcfs进程,并设置开机启动
最后验证查看启动状态
如果你遇到
Process: 25502 ExecStopPost=/usr/bin/fusermount -u /var/lib/lxcfs (code=exited, status=1/FAILURE)
的错误,目前看这是正常的。这样我们就可以验证结果了,输出的 cpu 数量就是 2。
用上面的 go 程序不能验证结果,这是因为 docker 具体而言使用了 CFS公平调度算法 限制容器的 CPU 使用,虽然 lxcfs 成功挂载了必要信息到
/proc/cpuinfo
里,但是 golang 运行时通过 sched_getaffinity系统调用来获取 cpu 数量,所以 lxcfs 还是不能彻底解决问题。这个问题目前没有解决,可以订阅这个 golang: runtime: make GOMAXPROCS cfs-aware on GOOS=linux 问题进行跟踪。上面介绍的 uber 开源的 automaxprocs 库解决这个问题的思路是读取 cgroup 信息,然后在启动的时候就设置 GOMAXPROCS。
另外你用 lscpu不能验证结果,也是同样的道理,都是系统调用,lxcfs 并不能拦截系统调用。