Kubernetes中的CPU配置與編程語(yǔ)言的性能問題:從Linux CFS調(diào)度談起
使用 Kubernetes 时,你可以通过 resources.requests
和 resources.limits
设置资源请求和限制,比如说:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: 应用容器
image: nginx
resources:
requests:
cpu: "250m"
limits:
cpu: "500m"
容器的资源配置通过CRI
组件(例如containerd
,cri-o
)通过底层运行时如runc
或kata-container
来实现,并应用到Linux的cgroups
系统。
在 cgroup v1(目前比较主流的版本,而 v2 正在开发中):
requests.cpu
对应于 cgroup 中的cpu.shares
。cpu.shares = 1024
表示一个 CPU 内核。对于requests.cpu = 250m
(0.25 个核心),等效的cpu.shares
是1024 * 0.25 = 256
。此配置仅在 CPU 资源竞争时生效,决定容器间如何按比例分配 CPU 时间。limits.cpu
对应以下 cgroup 参数:cpu.cfs_period_us
:指定 CPU 调度周期,通常为 100000 微秒(100 毫秒)。cpu.cfs_quota_us
:表示容器在一个周期内最多能使用的 CPU 时间。对于limits.cpu = 500m
(0.5 个核心),对应的cpu.cfs_quota_us
为100000 * 0.5 = 50000
。
这些设置可以通过在容器内的 /sys/fs/cgroup/cpu/
或直接在主机的 /sys/fs/cgroup/cpu/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod<uid>.slice/cri-containerd-<uid>.scope/
中查看。
因此,在容器环境中,CPU 限制是通过 Linux 的 CFS 机制来执行的。这就引出了一个自然的问题:应用程序或编程语言在容器内感知到的 CPU 核数是怎样的?
在容器环境下的编程语言在使用CPU核心数量来设置协程、线程或进程时,可能会遇到意外的性能问题。
在 Go 中,goroutines
使用 GPM
(Goroutine-Processor-Machine)模型中进行调度,其中处理器的数量由 GOMAXPROCS
决定。默认情况下,GOMAXPROCS
设置为 runtime.NumCPU()
,这会根据主机的 CPU 核心数进行设置。这可能会增加应用程序的延迟,尤其是在容器的 CPU 配额较小时,而主机资源相对充裕时。
解决方法是设置 GOMAXPROCS = max(1, 取整(floor)(cpu_quota))
,或者使用 uber-go/automaxprocs
这个库。更多细节可以在这里找到:https://github.com/golang/go/issues/33803。
在 Java 中,JVM 的垃圾收集机制与 Linux 的 CFS 调度程序之间的交互可能导致长时间的 STW(Stop-The-World,停止世界)事件。LinkedIn 的工程师在其博文《在 Linux 控制组中运行 JVM 时的应用程序暂停》中建议,应分配足够的 CPU 配额,并根据具体情况调整 GC 线程。
更好的做法是通过显式设置与容器资源限制相关的配置来消除模糊性。
最后的总结Kubernetes工作负载的CPU配额会指导Linux CFS的行为,这可能会导致意想不到的性能问题,特别是在应用程序的执行中。
参考:
共同學(xué)習(xí),寫下你的評(píng)論
評(píng)論加載中...
作者其他優(yōu)質(zhì)文章