pyroscope: 一个简单易用的持续剖析平台

开发人员常常需要跟踪生产环境中的应用程序的性能瓶颈,并试图找出造成瓶颈的根本原因。要做到这一点,他们通常会通过日志来收集这些信息。不幸的是,这种方法可能会很耗时,而且无法提供有关潜在问题的足够详细的信息。

一种现代且更先进的方法是应用和使用profiling技术和工具,突出显示最慢的应用程序代码和消耗大部分资源(如CPU和内存)的方法。持续分析(Continuous profiling)是在生产环境中持续 收集应用程序性能数据,并将这些数据提供给开发人员进行深入分析的过程。

通过,我们通过采集程序的指标,生成一个概要文件(Profile)进行单次的分析。Go语言提供了pprof工具,可以很方便的生成profile文件。你可以通过程序调用runtime/pprof生成CPU、Heap等概要文件,也可以使用net/http/pprof集成到web应用程序中,通过go tool pprof工具在命令行或者web页面中进行分析。

有时候,我们不能及时的进行pprof分析,故障可能消失了或者程序已经crash了。另外我们可能需要不同时段的profile进行对比,进行比较才能发现问题,比如内存泄露的问题。这个时候持续分析(continuous profiling)就很重要了。很多云服务厂商都提供持续分析的功能,比如Go Continuous Profiler | DatadogCloud Profiler | Google CloudAmazon CodeGuru Profiler等。

Pyroscope简介

如果你想在自己的生产系统中使用持续分析,可以考虑Pyroscope

Pyroscope是一个开源的持续分析系统,使用Go语言实现。服务端使用web页面查看,提供丰富的分析的功能,客户端提供Go、Java、Python、Ruby、PHP、.NET等多种语言的支持,并且支持PUSH、PULL两种采集方式。

deployment diagram

首先,你需要部署一个Pyroscope server,它底层采用BadgerDB作为存储引擎,对profile数据进行了优化处理。

Pyroscope server负责接收(或者拉取,下面我们主要演示推的方式)agent上传的profile数据,并提供时间线界面,可以查看一段时间以内的profile数据。比如下图演示了一个rpcx微服务程序12个小时的profile数据。

image-20220127133952215

它既可以显示这一段时间内的火焰图,也可以显示排序表格展示,或者同时显示。这个火焰图可以看出耗时主要在微服务的方法调用和编解码上(除了Go运行时调度)。

你还可以选取不同的时间段进行比较, 左右的图形的时间只需在时间线上拖拽选取即可。

image-20220127134555179

还可以进行diff查看,这个常常用在内存泄露的分析上。

image-20220127135630155

Pyroscope server安装

Pyroscope server端可以通过docker安装:

1
docker run -it -p 4040:4040 pyroscope/pyroscope:latest server

也可以在各中操作系统中直接安装。

比如Mac:

1
2
brew install pyroscope-io/brew/pyroscope
brew services start pyroscope-server

各Liunx发行版也方便安装,比如Cebtos:

1
2
3
4
wget https://dl.pyroscope.io/release/pyroscope-0.8.0-1-x86_64.rpm
sudo yum localinstall pyroscope-0.8.0-1-x86_64.rpm
sudo systemctl start pyroscope-server
sudo systemctl enable pyroscope-server

比如ubuntu:

1
2
wget https://dl.pyroscope.io/release/pyroscope_0.8.0_amd64.deb
sudo apt-get install ./pyroscope_0.8.0_amd64.deb

安装完成后,就可以通过web界面访问了: http://localhost:4040, 你可以通过配置文件更改监听端口以及其它一些配置项。

客户端集成

上面已经提到,Pyroscope提供了好几种语言的agent sdk, 我们以Go Push方式为例。在你需要持续分析的应用程序的开始加入agent的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pyroscope.Start(pyroscope.Config{
ApplicationName: "simple.golang.app",
// replace this with the address of pyroscope server
ServerAddress: "http://pyroscope-server:4040",
// you can disable logging by setting this to nil
Logger: pyroscope.StandardLogger,
// by default all profilers are enabled,
// but you can select the ones you want to use:
ProfileTypes: []pyroscope.ProfileType{
pyroscope.ProfileCPU,
pyroscope.ProfileAllocObjects,
pyroscope.ProfileAllocSpace,
pyroscope.ProfileInuseObjects,
pyroscope.ProfileInuseSpace,
},
})

主要配置ApplicationName的名称,这个名称会显示在Pyroscope的服务端下拉框中。profile数据要发送到哪一个Pyroscope服务器上,你可以配置ServerAddress,以及通过ProfileTypes监控要监控的Profile项。

只需加上这几行启动程序后,你就可以在Pyroscope server的web界面上查看持续分析的数据了。