您当前的位置:首页 > 电脑百科 > 程序开发 > 容器

理解Go、容器以及Linux调度器

时间:2023-12-18 14:15:22  来源:微信公众号  作者:DeepNoMind

Go开发的应用程序通常部署在容器中。在容器中运行时,重要的一点是要设置CPU限制以确保容器不会耗光主机上的所有CPU。但Go运行时不知道容器上设置的CPU限制,因此有可能会把所有可用的CPU都用光,从而造成应用延迟很高。这个问题曾经困扰过我,在这篇文章中,我将解释发生了什么以及如何修复。

Go垃圾收集器是如何工作的

这是对Go垃圾收集器(GC)的概要介绍,想要更深入了解,建议阅读Go文档[2]以及Will Kennedy的系列文章[3]。

绝大多数情况下,Go运行时在执行程序的同时执行垃圾收集,这意味着GC会与程序同时运行。然而,在GC过程中有两个点需要Go运行时暂停所有Goroutine,从而确保数据完整性。在GC标记阶段(Mark Phase)之前,运行时将暂停所有Goroutine,用以启用写屏障(write barrier),确保在此之后创建的任何对象都不会被GC,这个阶段称为扫描终止(Sweep Termination)。在标记阶段完成后,还有一个STW(stop the world)阶段,被称为标记终止(Mark Termination),并且也是删除写屏障的过程。整个流程通常需要几十微秒。

我创建了一个简单的web应用,分配了大量内存,并使用以下命令在一个限制为4个CPU核的容器中运行,源代码在Github[4]上。

Docker run --cpus=4 -p 8080:8080 $(ko build -L mAIn.go)

值得注意的是,docker CPU限制是硬性限制。可以设置--CPU-shares,表示只在主机CPU受限时强制执行。这意味着如果主机有空闲容量,容器可以使用超出分配的CPU核。但是如果主机资源受限,那么应用程序也将受到限制。

可以使用runtime/trace[5]包收集trace,然后用go tool trace对其进行分析。下面的trace显示了在我的机器上捕获的一个GC周期,可以看到在Proc 5中STW阶段的扫描终止和标记终止。

理解Go、容器以及Linux调度器

这个GC周期只花了不到2.5ms,但我们在STW阶段花费了近10%的时间。这是相当长的一段时间,特别是对于延迟敏感应用来说。

linux调度器

完全公平调度程序(Complete Fair Scheduler, CFS)[6]是在Linux 2.6.23中引入的,在2023年10月份发布的Linux 6.6之前一直是默认调度程序,很可能你正在使用CFS。

CFS是一个比例共享调度器[7],意味着进程权重与允许使用的CPU内核数量成正比。例如,如果允许一个进程使用4个CPU核,那么它的权重将为4。如果一个进程被允许使用2个CPU核心,它的权重将为2。

CFS通过分配一小部分CPU时间来实现,一个4核系统每秒钟有4秒的CPU时间可以分配。当我们为容器分配多个CPU内核时,实际上是要求Linux调度器给它n个CPU的时间。

在上面的docker run命令中,指定了4个CPU,意味着容器每秒将获得4秒的CPU时间。

问题

当Go运行时启动时,为每个CPU内核创建一个操作系统线程。这意味着如果有一个16核的机器,Go运行时将创建16个操作系统线程,不管任何CGroup CPU限制。然后Go运行时使用这些操作系统线程来调度程序。

问题是Go运行时不知道CGroup的CPU限制,而是在所有16个操作系统线程上调度goroutine,意味着Go运行时预计每秒能够使用16秒的CPU时间。

由于Go运行时需要在等待Linux调度器调度的线程上停止gooutine,因此将面临长时间的STW时间,因为一旦容器使用超过了CPU配额,线程就不会被调度。

解决方案

Go通过设置GOMAXPROCS环境变量限制运行时将创建的CPU线程数量。这一次,使用以下命令来启动容器:

docker run --cpus=4 -e GOMAXPROCS=4 -p 8080:8080 $(ko build -L main.go)

下面是从与上面相同的应用程序捕获的trace,现在使用与CPU配额匹配的GOMAXPROCS环境变量。

理解Go、容器以及Linux调度器

在这个trace中,尽管负载完全相同,但垃圾收集时间要短得多。GC周期小于1ms,STW时间为26μs,约为无限制时的1/10。

GOMAXPROCS应该设置为容器允许使用的CPU核数,通常情况应该向下取整,如果分配的CPU内核少于1个,则向上取整。可以用GOMAXPROCS=max(1, floor(cpu))来计算。Uber开源了一个库automaxprocs[8]来自动从容器的cgroups中计算这个值。

有一个Github问题[9]支持将这个特性添加到Go运行时中,使其开箱即用,希望最终会被Go运行时接受!

结论

在容器化应用程序中运行Go时,设置CPU限制非常重要。通过设置合理的GOMAXPROCS值或使用像automaxprocs这样的库,确保Go运行时意识到这些限制也很重要。

参考资料

[1]Go, Containers, and the Linux Scheduler: https://www.riverphillips.dev/blog/go-cfs

[2]Go文档: https://tip.golang.org/doc/gc-guide

[3]Garbage Collection In Go: https://www.ardanlabs.com/blog/2018/12/garbage-collection-in-go-part1-semantics.html

[4]示例代码: https://github.com/RiverPhillips/go-cfs-blog

[5]runtime/trace package: https://golang.org/pkg/runtime/trace

[6]完全公平调度程序(Complete Fair Scheduler, CFS): https://docs.kernel.org/scheduler/sched-design-CFS.html

[7]Proportional share scheduling: https://en.wikipedia.org/wiki/Proportional_share_scheduling

[8]automaxprocs: https://github.com/uber-go/automaxprocs

[9]Github问题: https://github.com/golang/go/issues/33803



Tags:容器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
掌握Docker网络驱动程序:优化容器通信
Docker为在容器内包装、交付和运行应用程序提供了一个强大的平台,从而彻底改变了容器化。网络是容器化的重要组成部分,Docker提供了各种网络驱动程序来支持容器之间的通信以...【详细内容】
2024-03-22  Search: 容器  点击:(10)  评论:(0)  加入收藏
Containerd容器管理
Nginx 指定容器名称 使用 ctr container create 命令创建容器后,容器并没有处于运行状态,其只是一个静态的容器。容器基本操作容器基本操作主要是 ctr image 命令,查看命令帮...【详细内容】
2024-03-20  Search: 容器  点击:(13)  评论:(0)  加入收藏
我们一起聊聊容器资源自愈
在企业实际在使用容器这类资源的时候,除了技术本身,要考虑的其他问题也会很多。企业管理的容器有千千万万,出于效率考虑,对于有特殊需求的容器如何进行批量创建和管理呢,这就需要...【详细内容】
2024-01-30  Search: 容器  点击:(47)  评论:(0)  加入收藏
Docker镜像与容器的交互及在容器内部执行代码的原理与实践
Docker作为一种流行的容器技术,已经成为现代应用程序开发和部署的重要工具。在Docker中,镜像是构建和运行容器的基础,而容器则是基于镜像创建的可执行实例。Docker镜像与容器的...【详细内容】
2024-01-10  Search: 容器  点击:(75)  评论:(0)  加入收藏
Go微服务入门到容器化实践
Go微服务入门到容器化实践Go 是一门高效、现代化、快速增长的编程语言,非常适合构建 Web 应用程序。而 Docker 是一种轻量级的容器化技术,能够使得您的应用程序在任何地方运行...【详细内容】
2024-01-01  Search: 容器  点击:(61)  评论:(0)  加入收藏
容器的“边缘”
译者 | 布加迪审校 | 重楼近年来边缘计算和容器越来越受欢迎,为我们日常生活中与数据处理相关的各种挑战提供了创新的解决方案。这些技术现在已经渗入到各种设备中,包括我们的...【详细内容】
2023-12-25  Search: 容器  点击:(161)  评论:(0)  加入收藏
Docker容器如何打包应用程序的代码和依赖项?
Docker容器通过将应用程序的代码和所有依赖项打包到一个独立的软件包中,实现了应用程序的快速部署和移植。下面是Docker容器实现这一目标的步骤:打包应用程序:使用Docker工具将...【详细内容】
2023-12-20  Search: 容器  点击:(130)  评论:(0)  加入收藏
理解Go、容器以及Linux调度器
Go开发的应用程序通常部署在容器中。在容器中运行时,重要的一点是要设置CPU限制以确保容器不会耗光主机上的所有CPU。但Go运行时不知道容器上设置的CPU限制,因此有可能会把所...【详细内容】
2023-12-18  Search: 容器  点击:(120)  评论:(0)  加入收藏
Docker容器编排技术解析
一、容器编排介绍容器编排是现代云原生应用管理的核心,它涉及在大规模的环境中自动化部署、管理、扩展和网络配置容器。随着微服务架构的兴起和应用的复杂性增加,容器编排成为...【详细内容】
2023-12-15  Search: 容器  点击:(244)  评论:(0)  加入收藏
在Linux系统中实现容器化的大规模数据分析平台:Hadoop和Spark
在Linux系统中实现容器化的大规模数据分析平台,我们可以利用Hadoop和Spark这两个强大的开源工具。Hadoop是一个分布式计算框架,适用于处理大规模数据集。它提供了分布式文件系...【详细内容】
2023-12-15  Search: 容器  点击:(154)  评论:(0)  加入收藏
▌简易百科推荐
Docker 和传统虚拟机有什么区别?
我有一个程序员朋友,他每年情人节都要送女朋友一台服务器。他说:“谁不想在过节当天收到一台 4核8g 的服务器呢?”“万一对方不要,我还能留着自己用。” 给他一次过节的机会,他能...【详细内容】
2024-03-26  小白debug  微信公众号  Tags:Docker   点击:(11)  评论:(0)  加入收藏
掌握Docker网络驱动程序:优化容器通信
Docker为在容器内包装、交付和运行应用程序提供了一个强大的平台,从而彻底改变了容器化。网络是容器化的重要组成部分,Docker提供了各种网络驱动程序来支持容器之间的通信以...【详细内容】
2024-03-22    51CTO  Tags:Docker   点击:(10)  评论:(0)  加入收藏
Containerd容器管理
Nginx 指定容器名称 使用 ctr container create 命令创建容器后,容器并没有处于运行状态,其只是一个静态的容器。容器基本操作容器基本操作主要是 ctr image 命令,查看命令帮...【详细内容】
2024-03-20  云原生运维圈  微信公众号  Tags:容器   点击:(13)  评论:(0)  加入收藏
如何基于Docker镜像逆向生成Dockerfile
引言你是否曾经遇到过一个想要使用的 Docker 镜像,但却无法修改以适应你的特定需求?或者你可能发现了一个喜欢的 Docker 镜像,但想要了解它是如何构建的?在这两种情况下,将 Docke...【详细内容】
2024-03-07  云原生运维圈  微信公众号  Tags:Docker   点击:(22)  评论:(0)  加入收藏
Kubernetes是什么?主要特点是什么?
Kubernetes是什么?Kubernetes,也称为K8s,是一个开源的容器编排系统,由Google首次开发和维护。它允许容器化的应用程序在集群中自动部署、扩展和管理。Kubernetes提供了一种容器...【详细内容】
2024-02-01    简易百科  Tags:Kubernetes   点击:(153)  评论:(0)  加入收藏
我们一起聊聊容器资源自愈
在企业实际在使用容器这类资源的时候,除了技术本身,要考虑的其他问题也会很多。企业管理的容器有千千万万,出于效率考虑,对于有特殊需求的容器如何进行批量创建和管理呢,这就需要...【详细内容】
2024-01-30  匠心独运维妙维效  微信公众号  Tags:容器   点击:(47)  评论:(0)  加入收藏
Docker与Docker Compose入门:释放你应用部署的威力
今天给大家介绍一项强大而有趣的技能,那就是使用 Docker 和 Docker Compose 来释放你的应用部署的威力!无论你是一名开发人员还是系统管理员,掌握这个技能都将为你的工作带来巨...【详细内容】
2024-01-17  waynblog  微信公众号  Tags:Docker   点击:(65)  评论:(0)  加入收藏
Docker镜像与容器的交互及在容器内部执行代码的原理与实践
Docker作为一种流行的容器技术,已经成为现代应用程序开发和部署的重要工具。在Docker中,镜像是构建和运行容器的基础,而容器则是基于镜像创建的可执行实例。Docker镜像与容器的...【详细内容】
2024-01-10  编程技术汇  今日头条  Tags:Docker   点击:(75)  评论:(0)  加入收藏
如何在 Ubuntu 上安装 Docker
使用 Docker 意味着开启一个新的计算领域,但如果你刚刚开始使用 Docker,安装可能看起来是一项艰巨的任务。在 Ubuntu 上安装 Docker 有两种推荐的方法: 从 Ubuntu 的仓库安装 D...【详细内容】
2024-01-04    Linux中国  Tags:Docker   点击:(124)  评论:(0)  加入收藏
从Kubernetes的探针到DevOps
今天在群里又看有人问如何设置 Kubernetes 的探针,感觉要补充的话太多了,结合我们在一些 DevOps 项目中痛苦的体验,今天一劳永逸的全部说完,此外,也为大家展现一下为什么 DevOps...【详细内容】
2023-12-27  云云众生s  微信公众号  Tags:Kubernetes   点击:(113)  评论:(0)  加入收藏
站内最新
站内热门
站内头条