写点什么

Go 运行时:4 年之后

  • 2022-10-11
    北京
  • 本文字数:1884 字

    阅读完需:约 6 分钟

Go运行时:4年之后

自 2018 年以来,Go GC,以及更广泛的 Go 运行时,一直在稳步改进。近日,Go社区总结了 4 年来 Go 运行时的一些重要变化。


这些重要变化主要是:

  • sync.Pool 是一种 GC 感知的重用内存的工具,具有较低的延迟影响,并且能够比之前更有效地回收内存。(Go 1.13)

  • Go 运行时能够更主动地将不需要的内存返回给操作系统,减少了内存消耗和出现内存不足的可能性。这将减少最高 20%的空闲内存消耗。(Go 1.13 和 1.14)

  • 在许多情况下,Go 运行时能够更容易地抢占 goroutine,最高可减少 90%的 stop-the-world 延迟。(Go 1.14)

  • Go 运行时能够比以前更有效地管理计时器,特别是在拥有多核 CPU 的机器上。(Go 1.14)

  • 在大多数情况下,现在使用 defer 语句的函数调用的开销与常规函数调用一样少。点击这里观看 Gophercon 2020 的相关演讲。(Go 1.14)

  • 内存分配器的慢路径对 CPU 核心的伸缩性更好,将吞吐量提升了最多 10%,并将尾部延迟降低了最多 30%,特别是在高度并行的程序中。(Go 1.14 和 1.15)

  • Go 内存统计数据现在可以通过更细粒度、更灵活、更高效的 API(runtime/metrics 包)来访问。这将获取运行时统计信息的延迟减少了两个数量级(从毫秒到微秒)。(Go 1.16)

  • Go 调度器在寻找新任务时花费的 CPU 时间减少了 30%。(Go 1.17)

  • Go 代码现在在 amd64、arm64 和 ppc64 上遵循基于寄存器的调用约定,将 CPU 效率提升了最多 15%。(Go 1.17 和 1.18)

  • Go GC 的内部审计和调度已经进行了重新设计,解决了长期存在的各种与效率和健壮性相关的问题。对于 goroutine 占内存使用很大一部分的应用程序来说,这显著降低了应用程序的尾部延迟(最高达 66%)。(Go 1.18)

  • Go GC 现在在应用程序空闲时会限制自己的 CPU 使用。这将空闲应用程序的 GC 周期的 CPU 使用降低了 75%,从而减少可能导致作业调度器混淆的 CPU 峰值。(Go 1.19)


这些变化对用户来说大多是看不见的——他们只需要升级 Go,就可以看到他们所熟悉和喜爱的 Go 代码运行得更好了。


一个新的“旋钮”


Go 1.19 带来了一个期待已久的特性,使用这个特性需要做一些额外的工作,但它具备很大的潜力:Go 运行时的软内存限制。


多年来,Go GC 只有一个调优参数——GOGC。GOGC 允许用户在 CPU 开销和内存开销之间做出权衡。多年来,这个“旋钮”为 Go 社区提供了很好的服务,被用在各种各样的场景中。


Go 运行时团队一直不愿意在 Go 运行时中添加新的旋钮,他们的理由很充分——每个新的旋钮代表了配置空间中的一个新的维度,我们需要对其进行测试和维护,而且可能要永远持续下去。旋钮的激增也给 Go 开发人员增加了理解和使用它们的负担,随着旋钮的增多,情况会变得愈加困难。因此,Go 运行时总是倾向于用最小配置实现合理的行为。


那么为什么要添加内存限制旋钮呢?


内存不像 CPU 时间那么具有可互换性。对于 CPU 时间,如果稍等片刻,将来总会得到更多的 CPU 时间。但对于内存,你所拥有的总是有限的。


内存限制解决了两个问题。


首先,当应用程序的内存使用峰值不可预测时,仅靠 GOGC 几乎无法防止内存被耗尽。如果只使用 GOGC,Go 运行时根本不知道它有多少可用的内存。通过设置内存限制,运行时能够意识到什么时候需要更努力地工作以减少内存开销,从而使运行时能够健壮地应对瞬时的、可恢复的负载峰值。


第二是为了避免不使用内存限制时出现的内存不足。我们必须根据内存峰值调优 GOGC,而为了保持较低的内存开销会导致更高的 GC CPU 开销,即使应用程序没有处于内存使用峰值且有足够的可用内存。这在容器化的环境中尤其重要。在容器化的环境中,程序被部署在具有独立预留内存的容器中。设置内存限制可以为峰值负载提供保护,并可以针对 CPU 开销更主动地调优 GOGC。


内存限制的设计旨在易用性和健壮性。例如,它是对应用程序中 Go 部分的整个内存占用的限制,而不仅仅是 Go 的堆,因此用户不需要额外计算 Go 运行时的开销。运行时还会根据内存限制调整其内存清除策略,以便在内存出现压力时更主动地将内存返回给操作系统。


虽然内存限制是一个强大的工具,但在使用时仍然要谨慎。其中一个需要注意的地方是,它会让你的程序陷入 GC 抖动状态——在这种状态下,程序运行 GC 的时间过多,导致没有足够的时间来处理其他任务。例如,如果内存限制设置得比程序实际需要的内存少,Go 程序可能会崩溃。以前不太可能出现 GC 抖动,除非显式对 GOGC 进行了大量调优。我们选择让内存耗尽而不是陷入抖动状态,因此作为一种缓解措施,运行时将 GC 限制为总 CPU 时间的 50%,即使这样会超过内存限制。


所有这些都需要慎重考虑,因此,作为这项工作的一部分,我们发布了一个新的 GC 指南,其中包含了交互式可视化的图表,以帮助你们理解 GC 成本以及如何操作它们。


更多可以查看 GC 指南:https://go.dev/doc/gc-guide


原文链接:https://go.dev/blog/go119runtime

2022-10-11 17:355768

评论

发布
暂无评论
发现更多内容

作业-用例文档

让我思考一会儿

微服务架构:网关概念与zuul

程序员架构进阶

服务化 API网关 七日更 28天写作 2月春节不断更

(28DW-S8-Day1) 定个魔幻的范围:在线教育+区块链

mtfelix

比特币 区块链 在线教育 28天写作 教育+区块链

翻译:《实用的Python编程》02_01_Datatypes

codists

Python 人工智能 数据结构与算法 字典 元组

MySQL 批量修改所有表字段字符集及排序规则

运维研习社

MySQ

滴普技术荟-云原生基座OpenKube开放容器实践(九):K8S的ServiceIP实现原理

mathtype的几个操作技巧

克比

腾讯发布区块链产业加速器,生态共创助力新基建建设

CECBC

腾讯

吉利汽车宣布进军区块链 多个龙头股企业早已低调精准布局区块链

CECBC

区块链

干货 | Redis 实现发布订阅原理与实践

架构精进之路

redis 28天写作 发布订阅

28天瞎写的第二百三十九天:什么是正念冥想?

树上

冥想 28天写作 正念

Let's Encrypt签发工具CertBot-auto不再维护

运维研习社

滴普技术荟-云原生基座OpenKube开放容器实践(八):flannel-vxlan模式原理解析

计算机中的层次化存储是个什么鬼?

冰河

程序员 数据结构 算法 计算机 层次化存储

关于智商测试的一点闲话 Day1

道伟

科普 28天写作

让代码说话:如何把版本信息注入到代码中

zhujun

c++ Python git rust Go 语言

这才是打开“金三银四”Java面试的正确方式,2021“金三银四”看这个就对了

Java 架构 面试

心理学与游戏之现学现卖系列

Justin

心理学 28天写作 游戏设计

为什么ElasticSearch比MySQL更适合全文索引

程序员历小冰

数据库 lucene elasticsearch BitMap 跳表

Go1.16 发布

Rayjun

Go 语言

2021 Flutter从零开始之全栈开发,后台到在线教育APP上线。

人生如梦

flutter dart

互联网小拼,这一生的故事,你要看看吗《打工人的那些事》

谙忆

一起重新全面认识JWT-Json Web Token

谙忆

2020 年行摄回忆录(下)

穿过生命散发芬芳

生活 摄影

Hive底层原理:explain执行计划详解

五分钟学大数据

大数据 hive 二月春节不断更

最常见的10种Java异常问题!

Java架构师迁哥

Nginx零成本、易操作实现网站视频加速

运维研习社

nginx 流媒体 网站优化

Linux如何使用libudev获取USB设备VID及PID

夜猫西街

deepin20 安装英伟达闭源驱动的步骤详解

夜猫西街

在区块链的新浪潮中,为更多人争取“公平”

CECBC

区块链 新浪潮

程序员成长第十篇:从阅读代码开始

石云升

28天写作 2月春节不断更 阅读代码

Go运行时:4年之后_语言 & 开发_Michael Knyszek_InfoQ精选文章