网站建设需要几个部门,收款网站怎么建设,有没有做ppt好看的免费网站,广州建站外包公司历史长原文#xff1a;Michael Knyszek - 2024.03.14
runtime/trace 包含了一款强大的工具#xff0c;用于理解和排查 Go 程序。这个功能可以生成一段时间内每个 goroutine 的执行追踪。然后#xff0c;你可以使用 go tool trace 命令#xff08;或者优秀的开源工具 gotraceuiMichael 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 {blockedif 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。
你们所有人的讨论、反馈和投入的工作对我们取得今天的成就发挥了重要作用谢谢你们