Go、容器以及Linux调度器

在容器中运行Go应用程序时,需要设置合理的GOMAXPROCS,从而避免调度中因为资源不足而造成STW。原文: Go, Containers, and the Linux Scheduler

alt

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

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

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

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

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

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

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

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

alt

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

Linux调度器

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

CFS是一个比例共享调度器[4],意味着进程权重与允许使用的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环境变量。

alt

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

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

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

结论

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


你好,我是俞凡,在Motorola做过研发,现在在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。为了方便大家以后能第一时间看到文章,请朋友们关注公众号"DeepNoMind",并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的支持和动力,激励我持续写下去,和大家共同成长进步!

参考资料
[1]

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

[2]

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

[3]

runtime/trace package: https://golang.org/pkg/runtime/trace

[4]

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

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/650551.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8-Seg改进:轻量化改进 | RepGhost,通过重参数化实现硬件高效的Ghost模块

🚀🚀🚀本文改进:RepGhost,通过重参数化实现硬件高效的Ghost模块,性能优于GhostNet、MobileNetV3等,在移动设备上具有更少的参数和可比的延迟。 🚀🚀🚀YOLOv8-seg创新专栏:http://t.csdnimg.cn/KLSdv 学姐带你学习YOLOv8,从入门到创新,轻轻松松搞定科研; 1…

CMU15-445 Project0

CMU14445 Task #1 - Copy-On-Write Trie Get()思路: 获取根节点指针,顺着key逐字符往下找节点,最后根据题意可以使用dynamic_cast检查是否是TrieNodeWithValue(dynamic_pointer_cast也可以),以下为两者用法&#xff1…

Making Large Language Models Perform Better in Knowledge Graph Completion论文阅读

文章目录 摘要1.问题的提出引出当前研究的不足与问题KGC方法LLM幻觉现象解决方案 2.数据集和模型构建数据集模型方法基线方法任务模型方法基于LLM的KGC的知识前缀适配器知识前缀适配器 与其他结构信息引入方法对比 3.实验结果与分析结果分析:可移植性实验&#xff1…

Web3 游戏开发者的数据分析指南

作者:lesleyfootprint.network 在竞争激烈的 Web3 游戏行业中,成功不仅仅取决于游戏的发布,还需要在游戏运营过程中有高度的敏锐性,以应对下一次牛市的来临。 人们对 2024 年的游戏行业充满信心。A16Z GAMES 和 GAMES FUND ONE …

网络安全热门岗位大盘点

网络安全已成为当今社会不可或缺的重要领域,国家和企业越来越重视网络安全,众多厂商也纷纷加大网络安全岗位的招聘力度。如果你对网络安全感兴趣,不妨了解一下这些热门岗位! 🎯首席信息官(CISO)…

【iOS ARKit】同时开启前后摄像头BlendShapes

在上一节中已经了解了 iOS ARkit 进行BlendShapes的基本操作,这一小节继续实践同时开启前后摄像头进行人脸捕捉和世界追踪。 iOS设备配备了前后两个摄像头,在运行AR 应用时,需要选择使用哪个摄像头作为图像输人。最常见的AR 体验使用设备后置…

vue项目中使用Element多个Form表单同时验证

一、项目需求 在项目中一个页面中需要实现多个Form表单,并在页面提交时需要对多个Form表单进行校验,多个表单都校验成功时才能提交。 二、实现效果 三、多个表单验证 注意项:多个form表单,每个表单上都设置单独的model和ref&am…

单片机学习笔记---矩阵键盘密码锁

目录 一,设置密码按键 1.设置密码区域 2.设置输入的数字左移 3.设置记录按键的次数 二,设置确认键 1.密码正确时显示OK 2.密码错误时显示ERR 3.密码错误恢复初始状态重输 三,设置取消键 学了这么久,迫不及待想要做一个密…

bind函数的认识与基本使用

目录 测试代码 使用测试 预留参数测试 关于细节可以参考文献 第六节 std::bind 绑定器 - 知乎 (zhihu.com) 为了后续工作&#xff0c;需要了解bind的使用 简单来说就是为一个函数绑定一个参数&#xff0c;以方便后续调用函数的时候不需要传参进去 测试代码 #include <…

uni-app 接口封装,token过期,自动获取最新的token

一、文件路径截图 2、新建一个文件app.js let hosthttp://172.16.192.40:8083/jeecg-boot/ //本地接口 let myApi {login: ${host}wx/wxUser/login, //登录 } module.exports myApi 3、新建一个文件request.js import myApi from /utils/app.js; export const r…

HbuilderX报错“Error: Fail to open IDE“,以及运行之后没有打开微信开发者,或者运行没有反应的解决办法

开始 问题:HbuilderX启动时,打开微信开发者工具报错"Error: Fail to open IDE",以及运行之后没有打开微信开发者,或者运行没有反应的解决办法! 解决办法: 按照步骤一步一步完成分析,除非代码报错,否则都是可以启动的 第一步:检查HbuildX是否登录账号 第二步:检查微信…

运行adprep /forestprep扩展Active Directory架构

运行 adprep /forestprep 是为了扩展Active Directory架构&#xff0c;以便为整个林添加新版本Windows Server所支持的新类、属性和其他目录对象。在升级到更高版本的Windows Server并提升林功能级别之前&#xff0c;通常需要执行此操作。 以下是详细步骤&#xff1a; 确认环境…

C语言第十弹---函数(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 函数 1、函数的概念 2、库函数 2.1、标准库和头文件 2.2、库函数的使用方法 2.2.1、功能 2.2.2、头文件包含 2.2.3、实践 2.2.4、库函数文档的⼀般格式 …

SpringBoot之分页查询的使用

背景 在业务中我们在前端总是需要展示数据&#xff0c;将后端得到的数据进行分页处理&#xff0c;通过pagehelper实现动态的分页查询&#xff0c;将查询页数和分页数通过前端发送到后端&#xff0c;后端使用pagehelper&#xff0c;底层是封装threadlocal得到页数和分页数并动态…

1.22ABM仿真(netlogo),A*(简要)

NETLOGO ABM建模 A* &#xff0c;体现了当前的步数成本 H为启发值&#xff0c;由启发性公式决定&#xff0c; 就是成本F由两个要素确定&#xff0c;一个是实际位置的成本G&#xff0c;由其自身固定的地理位置决定&#xff0c;另一个是启发值H&#xff0c;由下一个位置与目标…

web安全学习笔记【07】——非http\https抓包

#知识点&#xff1a; 1、Web常规-系统&中间件&数据库&源码等 2、Web其他-前后端&软件&Docker&分配站等 3、Web拓展-CDN&WAF&OSS&反向&负载均衡等 ----------------------------------- 1、APP架构-封装&原生态&H5&flutter…

【JaveWeb教程】(30)SpringBootWeb案例之《智能学习辅助系统》的详细实现步骤与代码示例(3)员工管理的实现

目录 SpringBootWeb案例033. 员工管理3.1 分页查询3.1.1 基础分页3.1.1.1 需求分析3.1.1.2 接口文档3.1.1.3 思路分析3.1.1.4 功能开发3.1.1.5 功能测试3.1.1.6 前后端联调 3.1.2 分页插件3.1.2.1 介绍3.1.2.2 代码实现3.1.2.3 测试 3.2 分页查询(带条件)3.2.1 需求3.2.2 思路分…

SQL 面试总结

1. SQL的运行顺序 from --> where -- > group by -- > having -- > select -- > order by -- > limit 2. SQL常用知识 select 筛选的字段名称 from 后面跟数据库名称 where 条件筛选 distinct - 去重 select distinct name, age select count(distinct n…

x-cmd pkg | haxor-news - Hacker News CLI

目录 简介首次用户功能特点进一步探索 简介 haxor-news 是一个用于在终端上查看 Hacker News 的内容。它可以让你在命令行查看/过滤 Hacker News 的帖子、评论、用户信息等&#xff0c;如过去 60 分钟内发布的最新评论。 Hacker News 是一家由 Paul Graham 创建的关于计算机黑…

C++——IOStream

什么是IO&#xff1f; C语言和C&#xff0c;我们其实已经接触到了两个IO的概念 #include<stdio.h> #include<iostream> iostream&#xff0c;便是IO流&#xff0c;其中I表示in&#xff0c;O表示out&#xff0c;代表着用户的输入和终端的输出。在之前的C语法中&a…