blog icon indicating copy to clipboard operation
blog copied to clipboard

Pod 中获取到错误的 CPUS

Open xiaoxiaojx opened this issue 3 years ago • 5 comments

image

背景

同学 a 在 gitlab CI 上的单测运行失败了, 错误信息如下。于是他按照 jest/issues/8769 的建议,在运行单测的命令上加上了 --maxWorkers=2 的参数,发现不止没有报错了,单测运行的时间还快了 5 倍 ?! 所以询问我这是发生了什么化学反应🤔

  ● Test suite failed to run

    Call retries were exceeded

      at ChildProcessWorker.initialize (../node_modules/jest-worker/build/workers/ChildProcessWorker.js:193:21)

jest --maxWorkers

image

--maxWorkers 参数表示的是 jest 会开启多少个线程去完成所有的测试任务,默认值是 50% * os.cpus().length,相关的文档可见 Jest docs/cli#--maxworker

其实早在之前, 同学 b 就告诉了我,咱们的机器规格很高,比如 xxx 服务就有 96 核。所以我首先打印了一下单测节点的机器的配置,发现有 64 核。那么本次单测线程数就有了 32 个。

分析

我的猜想是 Jest 比如并行跑两个用例时,由于 Node 线程间内存不共享,每个线程中的用例如果 import 了同样的文件都会通过 tsTransform、babelTransform 去转译一次,做了大量的重复工作而导致的耗时严重。

Node 线程的实现可见之前写的一篇文章 【node 源码学习笔记】worker_threads 工作线程 ,另外关于如何提升 Node 线程之间大量数据交换的效率也是我近期一直关注学习的点,后面有机会整理分享一次。

接着我又去咨询运维的大佬,大佬说这里的 64 核是宿主机的,分配给单测节点的可能只有 5核。

那么这样看来, 多线程在需要大量共享数据的情况下会变慢,而现在更是运超了分到的 CPU 资源的 6 倍之多,造成速度如此之缓慢就是情理之中的。

可行的方案

接着我尝试搜索了一下 Node 如何能获取到 k8s 分配到的给容器的资源数量,没有搜索到可直接使用的方案, 仅下面的方案看上去比较接近一点。

该方案是把设置的 resources 参数通过环境变量 MY_CPU_LIMIT 的形式传递给容器,详细可见 Kubernetes 用 Container 字段作为环境变量的值

apiVersion: v1
kind: Pod
metadata:
  name: dapi-envars-resourcefieldref
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/busybox:1.24
      command: [ "sh", "-c"]
      args:
      - while true; do
          echo -en '\n';
          printenv MY_CPU_REQUEST MY_CPU_LIMIT;
          printenv MY_MEM_REQUEST MY_MEM_LIMIT;
          sleep 10;
        done;
      resources:
        requests:
          memory: "32Mi"
          cpu: "125m"
        limits:
          memory: "64Mi"
          cpu: "250m"
      env:
        - name: MY_CPU_REQUEST
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: requests.cpu
        - name: MY_CPU_LIMIT
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.cpu
        - name: MY_MEM_REQUEST
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: requests.memory
        - name: MY_MEM_LIMIT
          valueFrom:
            resourceFieldRef:
              containerName: test-container
              resource: limits.memory
  restartPolicy: Never

有趣的是本地 Docker 容器中 os.cpus().length 不是宿主机中的核数,而是 Docker Desktop 中 Resources 设置的 CPUS。

image

小结

同理现在的 Node 服务通过集群模式启动直接使用 os.cpus().length 也是有问题的,暂时写死并发的数量去解决。也在 CNode 社区提了一个问答 如何在容器内获取分配到的 cpu 资源数量, 看看有没有踩过坑的大佬有更好的办法 ~

2022-01-29 补充

经过评论区 @Kaijun 大佬指点, 借鉴 Go 的解决方案 https://github.com/uber-go/automaxprocs , 实现了一版 Node.js 方案 https://github.com/xiaoxiaojx/get_cpus_length ,多方测试后是可行的 ✅

xiaoxiaojx avatar Jan 05 '22 16:01 xiaoxiaojx

竟然从zhihu一路过来看到凯多大佬的 blog

go 社区有自动探测 container 内,通过 procfs 找到容器进程 cgroup 的信息,推算出容器自身的 cpu 限制 ,可以参考: https://github.com/uber-go/automaxprocs

node 社区可能没有相关的自适应的工具和包,可以尝试搞一个

Kaijun avatar Jan 29 '22 03:01 Kaijun

竟然从zhihu一路过来看到凯多大佬的 blog

go 社区有自动探测 container 内,通过 procfs 找到容器进程 cgroup 的信息,推算出容器自身的 cpu 限制 ,可以参考: https://github.com/uber-go/automaxprocs

node 社区可能没有相关的自适应的工具和包,可以尝试搞一个

哈哈,看来是熟人 😁 ,感谢大佬指点,我们再研究一下

xiaoxiaojx avatar Jan 29 '22 05:01 xiaoxiaojx

竟然从zhihu一路过来看到凯多大佬的 blog go 社区有自动探测 container 内,通过 procfs 找到容器进程 cgroup 的信息,推算出容器自身的 cpu 限制 ,可以参考: https://github.com/uber-go/automaxprocs node 社区可能没有相关的自适应的工具和包,可以尝试搞一个

哈哈,看来是熟人 😁 ,感谢大佬指点,我们再研究一下

也可以脑壳喊我 @chiji ✋

Kaijun avatar Jan 29 '22 06:01 Kaijun

竟然从zhihu一路过来看到凯多大佬的 blog go 社区有自动探测 container 内,通过 procfs 找到容器进程 cgroup 的信息,推算出容器自身的 cpu 限制 ,可以参考: https://github.com/uber-go/automaxprocs node 社区可能没有相关的自适应的工具和包,可以尝试搞一个

哈哈,看来是熟人 😁 ,感谢大佬指点,我们再研究一下

也可以脑壳喊我 @chiji ✋

原来是 chiji

snakeUni avatar Jan 30 '22 01:01 snakeUni

竟然从zhihu一路过来看到凯多大佬的 blog go 社区有自动探测 container 内,通过 procfs 找到容器进程 cgroup 的信息,推算出容器自身的 cpu 限制 ,可以参考: https://github.com/uber-go/automaxprocs node 社区可能没有相关的自适应的工具和包,可以尝试搞一个

哈哈,看来是熟人 😁 ,感谢大佬指点,我们再研究一下

也可以脑壳喊我 @chiji ✋

原来是 chiji

瞻仰各位大佬们

Kaijun avatar Jan 30 '22 03:01 Kaijun