将Go分析与跟踪连接起来

2022-02-13 18:48:42

发布:今天,我想就我们最近在Datadog上发布的一些新的评测功能分享一些想法。我将解释他们做什么,如何工作,以及哪些Go 1.18捐款是为了让事情顺利进行。

让我们从最终结果开始。假设您有一个100毫秒的跟踪,其中10毫秒用于数据库查询,但90毫秒仍然无法解释。

发生这种情况时,通常需要研究代码以寻找线索。你忘了一些追踪仪器了吗?是时候添加、重新部署并等待了。或者你需要优化你的围棋代码?如果是,怎么做?

这个工作流程是可管理的,但事实证明有更好的方法——我们可以使用分析数据来填补空白。这正是我们新的代码热点功能所做的。如下所示,我们的请求占用了90毫秒的CPU时间。这是一个很强的信号,可以让我们排除非CPU活动,如未指令的服务调用、互斥冲突、通道等待、睡眠等。

更棒的是,当点击“查看配置文件”按钮时,我们可以在CPU时间上查看每个请求的火焰图。这里我们可以看到,我们的时间都花在了JSON编码上。

由于我们的HTTP处理函数没有出现在堆栈跟踪中,我们还可以间接推断,这项工作是在处理请求的goroutine生成的后台goroutine中完成的。

除了使用概要文件分解跟踪信息外,我们还可以做相反的事情,按端点分解概要文件的CPU时间,如下所示。复选框可用于按端点过滤配置文件。

为了更容易理解随时间的变化,例如部署后,我们可以将这些数据绘制成图表。

这些功能建立在一个名为pprof标签的现有Go功能之上,该功能允许我们将任意键/值对附加到当前运行的goroutine。当生成新的goroutine时,这些标签会自动继承,因此它们会覆盖到代码的所有角落。关键的是,这些标签也集成到了CPU档案器中,因此它们会自动出现在它生成的CPU档案中。

因此,为了实现这个功能,我们修改了dd trace go库中的跟踪代码,以便在创建新的span时自动应用诸如span id和端点之类的标签。此外,当跨度完成时,我们会注意移除标签。这种实现的简化示例如下所示:

func StartSpan(ctx context.context,端点字符串)*span{span:=&span{id:rand.Uint64(),restoreCX:ctx}标签:=pprof。标签(";span#u id";,fmt.Sprintf(";%d";,span.id),";终点";,终点,)pprof。SetGoroutineLabels(pprof.WithLabels(ctx,labels))返回span}type span结构{id uint64 restoreCtx context.context}func(s*span)Finish(){pprof.SetGoroutineLabels(s.restoreCtx)}

我们的实际实现稍微复杂一些,还降低了泄露PII(个人身份信息)的风险。它会自动覆盖contrib包中的HTTP和gRPC包装,以及应用程序可能实现的任何自定义跟踪。

一旦我们的后端接收到跟踪和分析信息,我们就能够执行为本文前面展示的功能提供动力所需的查找。

作为实现这些新特性的一部分,我们做了很多测试,包括单元测试、微观基准测试、宏观基准测试等等。正如所料,这在我们的代码中暴露了问题,并允许我们快速修复它们。

稍微出乎意料的是,我们还在Go运行时中发现了几个问题,这些问题影响了pprof标签的准确性,以及总体上的CPU配置。好消息是,在社区的帮助下,Go维护人员和我们这边的贡献——所有这些问题都在即将发布的Go 1.18版本中得到了解决。

如果您对这方面的全部细节感兴趣,请查看附带的帖子:Go 1.18中的评测改进。

也就是说,除非你使用大量cgo,否则Go 1.17中的新功能应该已经非常适合你了。

我目前正在寻找对这些新功能感兴趣的人,以便获得反馈。

无论你是现有客户还是潜在客户,只要给我发一封电子邮件,我们就可以设置30分钟的缩放。为了让交易更甜蜜,我也很乐意回答一些常见的问题:)。

如果想快速入门,只需将下面的代码复制到应用程序中即可。

此外,您还可以查看这个完整工作的dd trace go演示应用程序,它显示了一个包括HTTP和PostgreSQL的集成。

包主要导入(";time";";gopkg.in/DataDog/dd trace go.v1/ddtrace/tracer";";gopkg.in/DataDog/dd trace go.v1/profiler";)func main(){const(env=";dev";service=";example";version=";0.1";)tracer.Start(tracer.WithEnv(env)、tracer.WithService(service)、tracer.WithService(version)、tracer.withprofilercodehospots(true)、tracer.WithProfilerEndpoints(true)、defer())tracer.Stop err:=profiler.Start(profiler.with服务(service),profiler。WithEnv(env),探查器。WithVersion(version),//在所有范围内,100%的时间内启用CPU分析以捕获热点信息//的功能。目前默认值为25%,但在//下一个dd trace go发行版中可能会发生变化。探查器。CPUDuration(60*time.s),分析器。WithPeriod(60*时间秒),如果出错无{panic(err)}延迟分析器。停止()/<;您的应用程序代码>;}

--Felix Geisendörfer通过RSS或电子邮件订阅此博客,或通过Twitter从我那里获取小的更新。