看看你的Go应用是否用了正确CPU核数

 更新时间:2023年06月27日 09:23:46   作者:spacewander  
这篇文章主要为大家介绍了Go应用正确的CPU核数分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

Go 的调度模型

Go 的调度模型是 GMP,其中 G 是 goroutine,M 是线程,P 是可用的 CPU 核数。多个 G 会共用一个 M。M 作为操作系统层面上的调度单位,在执行时需要绑定到 P。如果操作系统认为的某个 Go 进程可用的 CPU 数,和该进程认为的可用的 CPU 数不一致,那么即使把 M 绑定到某个 P 上,操作系统也不一定会执行这个线程。所以能否获取准确的可用 CPU 核数会影响 Go 的调度效率。

k8s 设置资源限制

当用户在 k8s 中设置了资源限制:

spec:
  containers:
  - name: app_written_by_go
    resources:
      limits:
        cpu: "4"

Go 会不会识别到可用的 CPU 为 4 呢?读者可能会认为,Go 作为一个云原生时代炙手可热的语言,应该内置了对 k8s 的支持,所以能够识别出来。但事实并非如此。

小实验

如果启动 Go 进程时没有指定 GOMAXPROCS 环境变量,那么会以 runtime.NumCPU() 的输出作为可用的 CPU 核数(也即 P 的值)。让我们加一下打印 NumCPU 的代码,会发现实际上输出的是 Node 上的 CPU 数目,跟 limits.cpu 无关。

runtime.NumCPU() 在 Linux 上是通过系统调用 sched_getaffinity 实现的,但这个系统调用只考虑绑定 CPU 核的情况,不涉及容器环境下 cgroup 对 CPU 资源的限制。以 docker 为例,docker run 时指定 --cpuset-cpus 可以设置容器运行时可以使用的 CPU 核的编号,但限制 CPU 的资源数主要用 --cpus=。只有前者(cpuset)是能被 sched_getaffinity 识别的。

具体见 https://docs.docker.com/config/containers/resource_constraint...。如果要想计算后者,那么需要读取机器上的 cgroup fs 文件。

有一个 Go 库支持读取 cgroup fs 并计算出准确的 GOMAXPROCS:

https://github.com/uber-go/automaxprocs它支持两种不同的 cgroup fs (cgroup v1 和 v2):

其中 v1 是读取文件 cpu.cfs_quota_us 和 cpu.cfs_period_us,并求两者的商。这两个文件通常位于 /sys/fs/cgroup/cpu/ 下面(automaxprocs 会读挂载信息来获取实际位置)。

v2 则是读取文件 cpu.max 里面对应表示 quota 和 period 的字段,并求两者的商。除法的结果不一定是整数,所以还有一个向下取整的过程。

存在“应该能够识别可用 CPU 数但在容器环境下实际办不到”这种问题的并不只有 Go 一个。Nginx / Envoy 也有无法识别 cgroup 配置的问题。据说 Rust 和 Java (OpenJDK 实现)有专门处理过 cgroup 配置。如果你的应用符合下面两点:

  • 计算密集型或主要业务逻辑在若干个固定的 worker 中完成
  • 会部署到容器环境中
    那么不妨看看所用的框架是否能正确处理 cgroup 配置。

附注:IBM 的员工曾经提过一个 CPU Namespace 的设计,封装每个进程可以看得到的 CPU 信息,避免诸如 CPU 分配不一致这样的“抽象泄漏”。不过后续就没有下文了。

以上就是看看你的Go应用真的用了正确的CPU核数吗的详细内容,更多关于Go应用CPU核数的资料请关注脚本之家其它相关文章!

相关文章

  • golang使用jaeger进行链路追踪

    golang使用jaeger进行链路追踪

    链路追踪是指在分布式系统中,将一次请求的处理过程进行记录并聚合展示的一种方法,目的是将一次分布式请求的调用情况集中在一处展示,本文将介绍golang如何使用jaeger进行链路追踪,需要的朋友可以参考下
    2024-06-06
  • 利用golang进行OpenCV学习和开发的步骤

    利用golang进行OpenCV学习和开发的步骤

    目前,OpenCV逐步成为一个通用的基础研究和产品开发平台,下面这篇文章主要给大家介绍了关于利用golang进行OpenCV学习和开发的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-09-09
  • golang metrics各个指标含义讲解说明

    golang metrics各个指标含义讲解说明

    这篇文章主要为大家介绍了golang metrics各个指标含义讲解说明,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Golang共享变量如何解决问题

    Golang共享变量如何解决问题

    协程之间的通信只能够通过通道。但是我们习惯于共享变量,而且很多时候使用共享变量能让代码更简洁。那么Golang共享变量如何解决问题,感兴趣的可以了解一下
    2021-12-12
  • Golang错误处理方式异常与error

    Golang错误处理方式异常与error

    我们在使用Golang时,不可避免会遇到异常情况的处理,与Java、Python等语言不同的是,Go中并没有try...catch...这样的语句块,这个时候我们如何才能更好的处理异常呢?本文来教你正确方法
    2023-01-01
  • Golang使用DuckDB查询Parquet文件数据的操作代码

    Golang使用DuckDB查询Parquet文件数据的操作代码

    本文介绍DuckDB查询Parquet文件的典型应用场景,掌握DuckDB会让你的产品分析能力更强,相反系统运营成本相对较低,为了示例完整,我也提供了如何使用Python导出MongoDB数据,需要的朋友可以参考下
    2025-01-01
  • Go语言入门之基础语法和常用特性解析

    Go语言入门之基础语法和常用特性解析

    这篇文章主要给大家讲解了Go语言的基础语法和常用特性解析,比较适合入门小白,文中通过代码示例介绍的非常详细,对我们学习Go语言有一定的帮助,需要的朋友可以参考下
    2023-07-07
  • golang中struct和[]byte的相互转换示例

    golang中struct和[]byte的相互转换示例

    这篇文章主要介绍了golang中struct和[]byte的相互转换示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Go语言实现图片快递信息识别的简易方法

    Go语言实现图片快递信息识别的简易方法

    这篇文章主要为大家介绍了Go语言实现图片快递信息识别的简易方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Golang字符串变位词示例详解

    Golang字符串变位词示例详解

    这篇文章主要给大家介绍了关于GoLang字符串变位词的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-10-10

最新评论