首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

在 Go 1.11 下调试延迟问题

首发于:https://studygolang.com/articles/13036

诊断和调试复杂系统是一件复杂的事。经常需要多个层次的诊断数据来弄清楚延迟问题可能的原因。

一个分布式系统由多个服务器组成,这些服务器互相依赖,共同完成对用户请求的服务。在任何时候,

系统中的一个进程可能会处理大量的请求。

在高并发的服务器中,没有容易的途径能将一个请求生命周期内的各个事件分离出来。

在高并发的服务器中,对于响应一个请求所发生的事件,我们没有很好的可见性。

随着 Go 在近些年来变成编写服务器的一门流行语言,我们意识到理解 Go 进程在一个请求的生命周期内发生了什么事的必要性。

在程序执行过程中会发生许多运行时活动:调度、内存分配、垃圾回收等等。但是要将用户代码与运行时事件关联起来,并帮助用户分析运行时事件如何影响他们的性能,这在过去是不可能的。

网站可靠工程师(SRE)可能会在诊断一个延迟问题时寻求帮助,并希望有人能帮助他们理解并优化一个特定的服务器。甚至对于那些精通 Go 的人来说,能够估计出运行时对于他们遇到的特定情况的影响,也是非常复杂的。

在系统外部的人看来,经历延迟问题时,他们仅知道的一个事实就是自己等待了超出预期的时间(356ms)才收到响应,除此之外他们不知道别的。

用户使用 GET 方法访问 /messages 时等待了 356 ms 才收到响应。

从那些能够接触到分布追踪的开发者的角度来看,看到延迟的明细及每个服务对于总的延迟贡献了多少是有可能的。通过分布式追踪,我们对于境况有更好的可见性。

通过你收集到的分布式追踪来看延迟明细。

在这种情况下,为了服务 /messages, 我们写了三个内部的 RPC: auth.AccessToken, cache.Lookup 和 spanner.Query。我们可以看到每个 RPC 对延迟贡献了多少。这个时候,我们看出是auth.AccessToken花费了比平时长的时间。

我们成功的将问题缩小到一个特定的服务。我们可以通过关联特定的进程查看 auth.AccessToken 的源码,找到导致高延迟的代码,或者我们可以随意看看这个问题是否会在某个验证服务的实例上重现。

在 Go 1.11 下,我们将对执行追踪器有额外的支持,以便能指出 RPC 调用时的运行时事件。有了这个新特性,对于一个调用生命周期所发生的事,用户可以收集到更多的信息。

在这个案例中,我们将聚焦于 auth.AccessToken 范围内的部分。在网络上一共花费了 30 + 18 µs,阻塞的系统调用 5µs,垃圾回收 21µs,真正执行 handler 花费了 123µs,其中大部分都花在序列化和反序列化上。

通过查看这一层次的详细信息,我们最终可以说我们很不幸的在 RPC 调用期间遇到了 GC,而且我们在序列化/反序列化上竟然花费了很长的时间。然后,工程师们就可以指出最近对于 auth.AccessToken 的消息进行的修改,从而改善性能问题。他们还可以看看垃圾回收是否经常会在关键路径上对这个请求的处理造成影响,对内存分配的方式进行优化。

Go 1.11

在 Go 1.11 下,Go 的执行追踪器将引入一些新的概念、API 及追踪特性:

用户事件及用户注解,参见 runtime/trace.

用户代码和运行时之间的关联。

执行追踪器与分布式追踪进行关联的可行性。

执行追踪器引入两个上层的概念:region及task,以便用户来对他们的代码进行插桩。

Region 是你希望收集追踪数据的代码区域。一个 region 开始和结束在同一个 goroutine 内。另一方面,task 是一个逻辑上的群组,将相关的 region 归在一起。一个 task 的开始和结束可以在不同的 goroutine 中。

我们预期用户为每个分布式追踪的 span 都启动一个执行追踪器,通过创建 region, 当问题发生时即刻启用执行追踪器,记录一些数据,分析输出,来对他们的 RPC 框架进行全面的插桩。

亲手进行测试

尽管这些新特性只能在 Go 1.11 中使用,你依然可以按照说明从源码安装。

我也推荐你在分布式追踪里试试。我最近在 Census 创建的 span 中增加了对执行追踪器中 task 的支持。

如果你用的是 gRPC 或者 HTTP,那么你不需要手动创建 span,因为他们已经自动创建好了。在你的 handler 里面,你可以简单的对接收到的 context 使用 runtime/trace。

注册 pprof.Trace 的 handler,当你需要用执行追踪器的数据进行诊断时进行数据收集。

如果你需要执行追踪器的数据,那就马上记录,并启动可视化工具:

接着你就可以在 /usertasks 看到由 helloworld.Greeter.SayHello 创建的执行追踪器任务的一个分布。

RPC task 的时间分布。

你可以点击 3981µs 的那个异常的 bucket,进一步分析在那个特定 RPC 的生命周期里发生了什么。

同时,/userregions 让你列出收集到的 region。你可以看到 connection.init 这个 region 以及所对应的多条记录。(注意到 connection.init 是为了演示而手动集成到 gRPC 框架的源码中的,更多的插桩工作还在进行中。)

region 的时间分布。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181220B15LPS00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券