Go 1.22 - 更加强大的 Go 执行跟踪

在这里插入图片描述

原文:Michael Knyszek - 2024.03.14

runtime/trace 包含了一款强大的工具,用于理解和排查 Go 程序。这个功能可以生成一段时间内每个 goroutine 的执行追踪。然后,你可以使用 go tool trace 命令(或者优秀的开源工具 gotraceui)来可视化和探索这些追踪数据。

追踪的魔力在于,它可以轻易地揭示出程序中那些难以通过其他方式看到的信息。例如,一个并发瓶颈可能是很多 goroutine 在同一个 channel 上阻塞,这在 CPU profile 中可能很难被看到,因为没有执行样本可以采样。但在执行追踪中,执行的缺失或不足 将以惊人的清晰度展现出来,被阻塞的 goroutine 的堆栈追踪将迅速指向问题根源。

在这里插入图片描述

Go 开发者甚至能够使用 任务、区域 和 日志 来对自己的程序进行插桩,以便将更高的关注点与底层执行细节进行关联。

问题

不幸的是,执行追踪中的丰富信息往往无法触及。历史上,四个主要问题阻碍了追踪的使用。

  • 追踪的开销很大。
  • 追踪的扩展性不强,可能会变得过大而无法分析。
  • 往往不清楚何时开始追踪以捕获特定的不良行为。
  • 鉴于缺乏用于解析和解释执行追踪的公共包,只有最具冒险精神的 gopher 才能编程分析追踪。

如果你在过去几年中使用过追踪,可能已经被这些问题中的一个或多个所困扰。但我们很高兴地分享,在过去的两个 Go 版本中,我们在这四个领域都取得了大的进步。

低开销的追踪

在 Go 1.21 之前,许多应用的追踪运行时开销大约在 10-20% 的 CPU 之间,这限制了追踪的使用情况,不能像 CPU profiling 那样持续使用。事实证明,追踪的大部分成本都归结于 traceback。运行时产生的许多事件都附带有堆栈追踪,这些对于实际识别 goroutine 在关键执行时刻的行为是非常有价值的。

感谢 Felix Geisendörfer 和 Nick Ripley 在优化 traceback 效率方面的工作,执行追踪的运行时 CPU 开销已经大幅降低,对于许多应用来说,现在只有 1-2%。你可以在 Felix 的精彩博客文章中关于这项工作的内容。

可扩展的追踪

追踪格式及其事件的设计主要考虑到了相对高效的数据生成和输出(emission),但需要工具来解析和保留整个追踪的状态。几百 MiB 的追踪可能需要几 GiB 的 RAM 来分析!

不幸的是,这个问题对于跟踪的生成方式至关重要。为了保持运行时开销低,所有事件都被写入等同于线程局部缓冲区的地方。但这意味着事件出现的顺序并非其真实顺序,追踪工具需要负责弄清楚究竟发生了什么。

使追踪在保持开销低的同时具有可扩展性的关键是,不定期地切分正在生成的追踪。每个切分点都会表现得有点像同时禁用和重新启用追踪。到目前为止的所有追踪数据都会代表一个完整且自包含的追踪,而新的追踪数据将无缝地接续前者。

你可能想象到,修复这个问题需要在运行时重新思考和重写追踪实现的很多基础部分。我们很高兴地说,这项工作在 Go 1.22 中完成,并且现在已经普遍可用。许多很好的改进随着重写一起出现,包括对 go tool trace 命令的一些改进。如果你感到好奇,所有的细节都在设计文档中。

(注意:go tool trace 仍然将完整的追踪加载到内存中,但现在已经可以移除这个限制,用于 Go 1.22+ 程序生成的追踪。)

Flight recording

假设你正在开发一个网络服务,一个 RPC 花费了很长时间。你不能在已经知道 RPC 花费了一段时间的点开始追踪,因为慢请求的根本原因已经发生并且没有被记录下来。

有一种可以帮助解决这个问题的技术,叫做 Flight recording,你可能已经在其他编程环境中熟悉了。Flight recording 的关键理念是,持续进行追踪,并始终保留最新的追踪数据,以便随时使用。然后,一旦发生了有趣的事情,程序就可以直接写出它所拥有的所有内容!

在追踪可以被切分之前,这基本上是无法实现的。但是,由于开销较低,连续跟踪现在是可行的,以及运行时现在可以在需要的时候随时切分追踪,结果,实现 Flight recording 非常简单。

因此,我们很高兴宣布一个 Flight recorder 实验特性,可在 golang.org/x/exp/trace 包中找到。

请试试看!下面是一个示例,设置了 Flight recorder 以捕获长时间的 HTTP 请求,以帮助你入门。

// 设置 Flight recorder 。
fr := trace.NewFlightRecorder()
fr.Start()// 设置并运行一个 HTTP 服务器。
var once sync.Once
http.HandleFunc("/my-endpoint", func(w http.ResponseWriter, r *http.Request) {start := time.Now()// 做一些事情...doWork(w, r)// 我们看到了一个长请求。拍摄一张快照!if time.Since(start) > 300*time.Millisecond {// 为了简单起见,只做一次,但你可以拍摄多于一张的快照。once.Do(func() {// 抓取快照。var b bytes.Buffer_, err = fr.WriteTo(&b)if err != nil {log.Print(err)return}// 将它写入一个文件。if err := os.WriteFile("trace.out", b.Bytes(), 0o755); err != nil {log.Print(err)return}})}
})
log.Fatal(http.ListenAndServe(":8080", nil))

如果你有任何反馈,无论是积极的还是消极的,都请分享到 proposal issue 中!

追踪 reader API

伴随着追踪实现的重写,我们也努力清理了其他的追踪内部工具,如 go tool trace。这促使我们尝试创建一个足够优秀,以至于可以分享的追踪 reader API,这个 API 能够让追踪数据更易于访问。

就像 Flight recorder 一样,我们很高兴宣布我们也有一个实验性的追踪 reader API,我们希望分享出来。它在与 Flight recorder 相同的包 golang.org/x/exp/trace 中可用。

我们认为它足够好以开始在其之上构建东西,所以请试试看!下面是一个示例,它测量了阻塞等待网络的 goroutine 阻塞事件的比例。

// 从 STDIN 开始读取。
r, err := trace.NewReader(os.Stdin)
if err != nil {log.Fatal(err)
}var blocked int
var blockedOnNetwork int
for {// 读取事件。ev, err := r.ReadEvent()if err == io.EOF {break} else if err != nil {log.Fatal(err)}// 处理事件。if ev.Kind() == trace.EventStateTransition {st := ev.StateTransition()if st.Resource.Kind == trace.ResourceGoroutine {id := st.Resource.Goroutine()from, to := st.GoroutineTransition()// 寻找阻塞的 goroutines,并计数。if from.Executing() && to == trace.GoWaiting {blocked++if strings.Contains(st.Reason, "network") {blockedOnNetwork++}}}}
}
// 打印我们找到的内容。
p := 100 * float64(blockedOnNetwork) / float64(blocked)
fmt.Printf("%2.3f%% instances of goroutines blocking were to block on the network\n", p)

就像 Flight recorder 一样,proposal issue 将是留下反馈的好地方!

我们要特别提一下 Dominik Honnef,他是早期的试用者,提供了很好的反馈,并且对 API 的旧版追踪提供了支持。

感谢你们!

这项工作在很大程度上得益于诊断工作组的帮助,这个工作组是一年多前由来自 Go 社区的各个利益相关者共同发起的,并向公众开放的。

我们想花一点时间感谢那些,在过去一年中经常参加诊断会议的社区成员:Felix Geisendörfer, Nick Ripley, Rhys Hiltner, Dominik Honnef, Bryan Boreham, thepudds。

你们所有人的讨论、反馈和投入的工作,对我们取得今天的成就发挥了重要作用,谢谢你们!

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

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

相关文章

【Java - 框架 - Knife4j】(01) SpringBoot整合Knife4j - 快速上手

“SpringBoot"整合"Knife4j” - 快速上手; 环境 “Knife4j"版本"2.0.9”;“Java"版本"1.8.0_202”;“Spring Boot"版本"2.5.9”;“Windows 11 专业版_22621.2428”;“Intel…

GPT-5可能会在今年夏天作为对ChatGPT的“实质性改进”而到来

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

Spring Web MVC入门(6)

应用分层 在开发的过程中, 我们会发现, 程序的代码有时会很"杂乱", 如果后面的项目更大了, 那就会更加地杂乱无章(文件乱, 代码内容乱). 也基于此, 接下来让我们来学习一下应用分层. 也类似于公司的组织架构 公司初创阶段, 一个人身兼数职, 既做财务, 又做人事,还有…

Unity多人游戏基础知识总结

作者简介: 高科,先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢你的关注…

【链表】Leetcode 19. 删除链表的倒数第 N 个结点【中等】

删除链表的倒数第 N 个结点 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5] 解题思路 1、使用快慢指针找到要删除节点的前一个节点。2、删…

【书生·浦语大模型实战营】学习笔记2

Lagent:智能体框架,实现将一个大语言模型转化为多种类型的智能体,更好地发挥InternLM的性能 浦语灵笔:视觉语言大模型 InternLM-Chat-7B智能对话Demo 环境准备 使用复制的internlm-demo环境 # 执行该脚本文件来安装项目实验环境…

[HackMyVM] Quick

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

如何在个人Windows电脑搭建Cloudreve云盘并实现无公网IP远程访问

文章目录 1、前言2、本地网站搭建2.1 环境使用2.2 支持组件选择2.3 网页安装2.4 测试和使用2.5 问题解决 3、本地网页发布3.1 cpolar云端设置3.2 cpolar本地设置 4、公网访问测试5、结语 1、前言 自云存储概念兴起已经有段时间了,各互联网大厂也纷纷加入战局&#…

再谈 Flink 的 “动态表” 和 “流表二象性”

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

基于Matlab的视频人体动作识别,Matlab实现

博主简介: 专注、专一于Matlab图像处理学习、交流,matlab图像代码代做/项目合作可以联系(QQ:3249726188) 个人主页:Matlab_ImagePro-CSDN博客 原则:代码均由本人编写完成,非中介,提供…

Ribbon知识点

1、通过类实现重写Ribbon规则 1.1注意 这个类一定不能跟启动类放在同一个包下面,不能被componentScan给扫描到。 需要如图放置: 要是被componentScan给扫描到,则会被所有的服务提供方所共享,那么就不能实现指定服务用不同的Ribbo…

一套键盘鼠标控制两台电脑 Mouse Without Borders

有两台电脑,一台笔记本一台台式机,拥有各自拥有鼠标和键盘,但总是需要切换,感觉太麻烦,想找个简单的方式,不需要额外操作就能同时操作这两台电脑。无意间发现了一个微软软件Mouse Without Borders&#xff…

Go语言学习04~05 函数和面向对象编程

Go语言学习04-函数 函数是一等公民 <font color"Blue">与其他主要编程语言的差异</font> 可以有多个返回值所有参数都是值传递: slice, map, channel 会有传引用的错觉函数可以作为变量的值函数可以作为参数和返回值 学习函数式编程 可变参数 func s…

Docker基本操作

我们可以通过 docker --help 查看所有命令 我们可以通过docker hub 拉取 Docker hub官网链接 接着 输入 docker images 查看刚才拉取的nginx镜像 镜像常见操作 docker imagesdocker rmidocker pulldocker pushdocker savedocker load

【图解物联网】第1章 物联网的基础知识

1.1 物联网入门 1.1.1 物联网 物联网的英语是Internet of Things&#xff0c;缩写为IoT&#xff0c;这里的“物”指的是我们身边一切能与网络相连的物品。只要能与网络相连&#xff0c;就都是物联网说的“物”。 物联网就是“物”之间通过连接互联网来共享信息并产生…

信息学奥赛之MAC端VSCode C++环境配置

前提 安装 Visual Studio CodeVSCode 中安装 C/C扩展确保 Clang 已经安装&#xff08;在终端中输入命令&#xff1a;clang --version 来确认是否安装&#xff09;未安装&#xff0c;在命令行执行xcode-select --install 命令&#xff0c;会自行安装&#xff0c;安装文件有点大…

如何将OpenCV Java 与Eclipse结合使用

返回目录&#xff1a;OpenCV系列文章目录 上一篇&#xff1a;OpenCV-Java 开发简介 下一篇&#xff1a;使用 Clojure 进行 OpenCV 开发简介 正文&#xff1a; 警告&#xff1a;本教程可以包含过时的信息。 从 2.4.4 版本开始&#xff0c;OpenCV 支持 Java。在本教程中&…

力扣454. 四数相加 II

思路&#xff1a;把四个数组拆成两对&#xff0c;两个分别相加&#xff0c;记录第一对的相加结果进map里&#xff0c;再把第二对数组 0-nums2-nums4 去map里面找出现了几次&#xff0c;这题不用对重复的四元组去重&#xff0c;所以出现多次都有效。 class Solution {public int…

vue3+ts+vite axios封装请求并扩展入参

requset.ts import axios, { AxiosResponse } from axios import { getToken, removeToken } from /utils/auth// 创建axios实例 const service axios.create({baseURL: , // 所有的请求地址前缀部分(没有后端请求不用写)timeout: 60000 // 请求超时时间(毫秒)// withCredent…

MySQL Workbench连接云服务器内网数据库

在项目上遇到一个问题&#xff0c;生产环境是Centos&#xff0c;分配了两台云服务器&#xff0c;一台应用服务&#xff0c;一台数据库服务&#xff0c;应用服务与数据库服务采用内网连接。我作为开发和运维方&#xff0c;有权限直接访问应用服务&#xff0c;但是数据库服务器需…