诊断和调试复杂系统很复杂。通常需要多级诊断数据才能了解延迟问题的可能原因。
分布式系统由许多服务器组成,这些服务器相互依赖以服务于用户请求。随时,
*系统中的进程可能正在处理大量请求。
*在高度并发的服务器中,没有简单的方法来隔离请求生命周期中发生的事件。
*在高度并发的服务器中,我们无法很好地了解为请求提供服务的事件。
随着Go成为近年来编写服务器的流行语言,我们意识到需要了解请求生命周期中Go过程中发生的事情。
程序执行期间会发生许多运行时活动:调度,内存分配,垃圾回收等。但是无法将用户代码与运行时事件相关联,并帮助用户分析运行时事件如何影响其性能。
SRE会请求帮助来诊断延迟问题,并想知道是否有人可以帮助他们理解和优化特定服务器。对于Go中的那些专家来说,能够估计运行时可能如何影响他们的具体情况是非常复杂的。
没有简单的方法来说明为什么某些请求的延迟很高。分布式跟踪允许我们定位要查看的请求处理程序,但我们需要深入研究。可能是因为GC,调度程序或I/O等我们等待响应吗? --SRE
从系统外部的人的角度来看,当遇到延迟问题时,除了他们知道他们等待超过预期(356毫秒)以获得响应的事实之外,他们并不知道太多。
从可以访问分布式跟踪的工程师的角度来看,可以看到细分以及每个服务如何对整体延迟做出贡献。通过分布式跟踪,我们可以更好地了解情况。
在这种情况下,为了服务/消息,我们制作了三个内部RPC:auth.AccessToken,cache.Lookup和spanner.Query。我们可以看到每个RPC如何影响延迟。此时,我们可以发现auth.AccessToken比平时花费的时间更长。
我们成功地将问题缩小到特定服务。我们可以通过将auth.AccessToken与特定进程相关联来找到它的来源,或者我们可以随机尝试查看该问题是否可以在任何auth服务实例上重现。
使用Go 1.11,我们将对执行跟踪器提供额外支持,以便能够通过RPC调用来定位运行时事件。利用这些新功能,用户将能够收集有关呼叫生命周期中发生的事情的更多信息。
在这种情况下,我们关注auth.AccessToken范围中的部分。我们总共花了30 +18μs用于联网,5μs用于阻塞系统调用,8μs用于垃圾收集,123μs实际执行处理程序,我们主要花时间进行序列化和反序列化。
通过查看这个详细程度,我们终于可以说我们很遗憾这个RPC与GC重叠,我们在序列化/反序列化上花费的金额不大。然后,工程师可以指出auth.AccessToken消息中的最近更改并改善性能问题。他们还可以查看GC是否经常影响关键路径上的此请求,并可能优化内存分配以查看它们是否可以改进此模式。
Go 1.11
使用1.11,Go执行跟踪器将引入一些新概念,API和跟踪功能:
*用户事件和用户注释,请参阅运行时/跟踪。
*用户代码和运行时之间的关联。
*将执行跟踪器数据与分布式跟踪相关联的可能性。
执行跟踪器为用户引入了两个高级概念来检测其代码:区域和任务。
区域是你要为其收集跟踪数据的代码中的部分。区域以相同的goroutine开始和结束。另一方面,任务更像是将相关区域分类在一起的逻辑组。任务可以以与它开始的goroutine不同的goroutine结束。
我们希望用户为他们拥有的每个分布式跟踪范围启动执行跟踪任务,通过创建区域来全面检测其RPC框架,在出现问题时立即启用执行跟踪器,记录一些数据并分析输出。
亲自尝试一下
尽管新功能只能在Go 1.11中使用,但你可以尝试安装Go from tip。
我还建议你尝试使用分布式跟踪。我最近为Census创建的跨度添加了执行跟踪器任务支持。
如果你正在使用gRPC和HTTP集成,则不必手动创建任何跨度,因为它们是为你自动创建的。在处理程序中,你可以简单地将运行时/跟踪与传入上下文一起使用。
注册pprof.Trace处理程序并在需要执行跟踪器数据进行诊断时收集数据:
然后,如果你想要执行跟踪器数据并启动工具可视化,请暂时记录数据:
然后,你可以在 /usertasks中看到为helloworld.Greeter.SayHello创建的执行跟踪器任务的分布。
你可以单击异常值延迟桶,3981μs,以进一步分析特定RPC生命周期中发生的情况。
/userregions还允许你列出收集的区域。你可以看到connection.init区域和记录数。(请注意,为了演示目的,将connection.init手动添加到gRPC框架代码中,更多关于仪器gRPC的工作仍在进行中。)
如果你单击任何链接,它将为你提供有关适合该延迟存储区的区域的更多详细信息。在下面的例子中,我们看到一个区域收集了1000μs桶。
然后你可以看到延迟的细粒度细分。你可以看到1309μs区域与垃圾收集重叠。它在GC工作和调度方面增加了关键路径上的更多开销。否则,执行处理程序和处理阻塞系统调用大致需要相同的时间。
限制
尽管新的执行跟踪器功能很强大,但仍有局限性。
*区域只能在同一个goroutine中启动和停止。执行跟踪器当前无法自动记录跨越多个goroutine的数据。这要求我们手动检测区域。下一个重要步骤是在RPC框架和标准软件包(如net / http)中添加更细粒度的工具。
*执行跟踪器的输出格式很难解析,而工具跟踪是唯一可以理解这种格式的规范工具。没有简单的方法可以自动将执行跟踪器数据附加到分布式跟踪 - 因此我们将它们单独收集并在以后进行关联。
结论
Go正在努力成为生产服务的优秀运行时。利用执行跟踪器提供的数据,我们更接近于对生产服务器具有高可见性,并在出现问题时提供更多可操作的数据。
领取专属 10元无门槛券
私享最新 技术干货