热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Golang大杀器之跟踪剖析trace

在Go中有许许多多的分析工具,在之前我有写过一篇《Golang大杀器之性能剖析PProf》来介绍PProf,如果有小伙伴感兴趣可以去我博客看看。但单单使

640?wx_fmt=png

在 Go 中有许许多多的分析工具,在之前我有写过一篇 《Golang 大杀器之性能剖析 PProf》 来介绍 PProf,如果有小伙伴感兴趣可以去我博客看看。

但单单使用 PProf 有时候不一定足够完整,因为在真实的程序中还包含许多的隐藏动作,例如 Goroutine 在执行时会做哪些操作?执行/阻塞了多长时间?在什么时候阻止?在哪里被阻止的?谁又锁/解锁了它们?GC 是怎么影响到 Goroutine 的执行的?这些东西用 PProf 是很难分析出来的,但如果你又想知道上述的答案的话,你可以用本文的主角 go tool trace 来打开新世界的大门。目录如下:

640?wx_fmt=png

初步了解

import ( "os" "runtime/trace"
)
func main() { trace.Start(os.Stderr) defer trace.Stop() ch :&#61; make(chan string) go func() { ch <- "EDDYCJY" }() <-ch
}

生成跟踪文件&#xff1a;

$ go run main.go 2> trace.out

启动可视化界面&#xff1a;

$ go tool trace trace.out
2019/06/22 16:14:52 Parsing trace...
2019/06/22 16:14:52 Splitting trace...
2019/06/22 16:14:52 Opening browser. Trace viewer is listening on http://127.0.0.1:57321

查看可视化界面&#xff1a;

640?wx_fmt&#61;png

  • View trace&#xff1a;查看跟踪

  • Goroutine analysis&#xff1a;Goroutine 分析

  • Network blocking profile&#xff1a;网络阻塞概况

  • Synchronization blocking profile&#xff1a;同步阻塞概况

  • Syscall blocking profile&#xff1a;系统调用阻塞概况

  • Scheduler latency profile&#xff1a;调度延迟概况

  • User defined tasks&#xff1a;用户自定义任务

  • User defined regions&#xff1a;用户自定义区域

  • Minimum mutator utilization&#xff1a;最低 Mutator 利用率

Scheduler latency profile

在刚开始时&#xff0c;我们一般先查看 “Scheduler latency profile”&#xff0c;我们能通过 Graph 看到整体的调用开销情况&#xff0c;如下&#xff1a;

640?wx_fmt&#61;png

因为演示程序比较简单&#xff0c;因此这里就两块&#xff0c;一个是 trace 本身&#xff0c;另外一个是 channel 的收发。

Goroutine analysis

第二步看 “Goroutine analysis”&#xff0c;我们能通过这个功能看到整个运行过程中&#xff0c;每个函数块有多少个有 Goroutine 在跑&#xff0c;并且观察每个的 Goroutine 的运行开销都花费在哪个阶段。如下&#xff1a;

640?wx_fmt&#61;png

通过上图我们可以看到共有 3 个 goroutine&#xff0c;分别是 runtime.mainruntime/trace.Start.func1main.main.func1&#xff0c;那么它都做了些什么事呢&#xff0c;接下来我们可以通过点击具体细项去观察。如下&#xff1a;

640?wx_fmt&#61;jpeg

同时也可以看到当前 Goroutine 在整个调用耗时中的占比&#xff0c;以及 GC 清扫和 GC 暂停等待的一些开销。如果你觉得还不够&#xff0c;可以把图表下载下来分析&#xff0c;相当于把整个 Goroutine 运行时掰开来看了&#xff0c;这块能够很好的帮助我们对 Goroutine 运行阶段做一个的剖析&#xff0c;可以得知到底慢哪&#xff0c;然后再决定下一步的排查方向。如下&#xff1a;

名称含义耗时
Execution Time执行时间3140ns
Network Wait Time网络等待时间0ns
Sync Block Time同步阻塞时间0ns
Blocking Syscall Time调用阻塞时间0ns
Scheduler Wait Time调度等待时间14ns
GC SweepingGC 清扫0ns
GC PauseGC 暂停0ns

View trace

在对当前程序的 Goroutine 运行分布有了初步了解后&#xff0c;我们再通过 “查看跟踪” 看看之间的关联性&#xff0c;如下&#xff1a;

640?wx_fmt&#61;png

这个跟踪图粗略一看&#xff0c;相信有的小伙伴会比较懵逼&#xff0c;我们可以依据注解一块块查看&#xff0c;如下&#xff1a;

  1. 时间线&#xff1a;显示执行的时间单元&#xff0c;根据时间维度的不同可以调整区间&#xff0c;具体可执行 shift &#43; ? 查看帮助手册。

  2. 堆&#xff1a;显示执行期间的内存分配和释放情况。

  3. 协程&#xff1a;显示在执行期间的每个 Goroutine 运行阶段有多少个协程在运行&#xff0c;其包含 GC 等待&#xff08;GCWaiting&#xff09;、可运行&#xff08;Runnable&#xff09;、运行中&#xff08;Running&#xff09;这三种状态。

  4. OS 线程&#xff1a;显示在执行期间有多少个线程在运行&#xff0c;其包含正在调用 Syscall&#xff08;InSyscall&#xff09;、运行中&#xff08;Running&#xff09;这两种状态。

  5. 虚拟处理器&#xff1a;每个虚拟处理器显示一行&#xff0c;虚拟处理器的数量一般默认为系统内核数。

  6. 协程和事件&#xff1a;显示在每个虚拟处理器上有什么 Goroutine 正在运行&#xff0c;而连线行为代表事件关联。

640?wx_fmt&#61;jpeg

点击具体的 Goroutine 行为后可以看到其相关联的详细信息&#xff0c;这块很简单&#xff0c;大家实际操作一下就懂了。文字解释如下&#xff1a;

  • Start&#xff1a;开始时间

  • Wall Duration&#xff1a;持续时间

  • Self Time&#xff1a;执行时间

  • Start Stack Trace&#xff1a;开始时的堆栈信息

  • End Stack Trace&#xff1a;结束时的堆栈信息

  • Incoming flow&#xff1a;输入流

  • Outgoing flow&#xff1a;输出流

  • Preceding events&#xff1a;之前的事件

  • Following events&#xff1a;之后的事件

  • All connected&#xff1a;所有连接的事件

View Events

我们可以通过点击 View Options-Flow events、Following events 等方式&#xff0c;查看我们应用运行中的事件流情况。如下&#xff1a;

640?wx_fmt&#61;png

通过分析图上的事件流&#xff0c;我们可得知这程序从 G1 runtime.main 开始运行&#xff0c;在运行时创建了 2 个 Goroutine&#xff0c;先是创建 G18 runtime/trace.Start.func1&#xff0c;然后再是 G19 main.main.func1 。而同时我们可以通过其 Goroutine Name 去了解它的调用类型&#xff0c;如&#xff1a;runtime/trace.Start.func1 就是程序中在 main.main 调用了 runtime/trace.Start 方法&#xff0c;然后该方法又利用协程创建了一个闭包 func1 去进行调用。

640?wx_fmt&#61;png

在这里我们结合开头的代码去看的话&#xff0c;很明显就是 ch 的输入输出的过程了。

结合实战

今天生产环境突然出现了问题&#xff0c;机智的你早已埋好 _"net/http/pprof" 这个神奇的工具&#xff0c;你麻利的执行了如下命令&#xff1a;

  • curl http://127.0.0.1:6060/debug/pprof/trace\?seconds\&#61;20 > trace.out

  • go tool trace trace.out

View trace

你很快的看到了熟悉的 List 界面&#xff0c;然后不信邪点开了 View trace 界面&#xff0c;如下&#xff1a;

640?wx_fmt&#61;jpeg

完全看懵的你&#xff0c;稳住&#xff0c;对着合适的区域执行快捷键 W 不断地放大时间线&#xff0c;如下&#xff1a;

640?wx_fmt&#61;jpeg

经过初步排查&#xff0c;你发现上述绝大部分的 G 竟然都和 google.golang.org/grpc.(*Server).Serve.func 有关&#xff0c;关联的一大串也是 Serve 所触发的相关动作。

640?wx_fmt&#61;jpeg

这时候有经验的你心里已经有了初步结论&#xff0c;你可以继续追踪 View trace 深入进去&#xff0c;不过我建议先鸟瞰全貌&#xff0c;因此我们再往下看 “Network blocking profile” 和 “Syscall blocking profile” 所提供的信息&#xff0c;如下&#xff1a;

Network blocking profile

640?wx_fmt&#61;jpeg

Syscall blocking profile

640?wx_fmt&#61;jpeg

通过对以上三项的跟踪分析&#xff0c;加上这个泄露&#xff0c;这个阻塞的耗时&#xff0c;这个涉及的内部方法名&#xff0c;很明显就是哪位又忘记关闭客户端连接了&#xff0c;赶紧改改改。

总结

通过本文我们习得了 go tool trace 的武林秘籍&#xff0c;它能够跟踪捕获各种执行中的事件&#xff0c;例如 Goroutine 的创建/阻塞/解除阻塞&#xff0c;Syscall 的进入/退出/阻止&#xff0c;GC 事件&#xff0c;Heap 的大小改变&#xff0c;Processor 启动/停止等等。

希望你能够用好 Go 的两大杀器 pprof &#43; trace 组合&#xff0c;此乃排查好搭档&#xff0c;谁用谁清楚&#xff0c;即使他并不万能。

参考

  • https://about.sourcegraph.com/go/an-introduction-to-go-tool-trace-rhys-hiltner

  • https://www.itcodemonkey.com/article/5419.html

  • https://making.pusher.com/go-tool-trace/

  • https://golang.org/cmd/trace/

  • https://docs.google.com/document/d/1FP5apqzBgr7ahCCgFO-yoVhk4YZrNIDNf9RybngBc14/pub

  • https://godoc.org/runtime/trace

640?wx_fmt&#61;png


推荐阅读
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
  • Annotation的大材小用
    为什么80%的码农都做不了架构师?最近在开发一些通用的excel数据导入的功能,由于涉及到导入的模块很多,所以开发了一个比较通用的e ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 在开发中,有时候一个业务上要求的原子操作不仅仅包括数据库,还可能涉及外部接口或者消息队列。此时,传统的数据库事务无法满足需求。本文介绍了Java中如何利用java.lang.Runtime.addShutdownHook方法来保证业务线程的完整性。通过添加钩子,在程序退出时触发钩子,可以执行一些操作,如循环检查某个线程的状态,直到业务线程正常退出,再结束钩子程序。例子程序展示了如何利用钩子来保证业务线程的完整性。 ... [详细]
  • Java编程思想一书中第21章并发中关于线程间协作的一节中有个关于汽车打蜡与抛光的小例子(原书的704页)。这个例子主要展示的是两个线程如何通过wait ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
author-avatar
仲颖凯翰奕颖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有