一 环境准备

1. systemtap 安装

1
2
3
$yum install systemtap
$yum install kernel-devel
$sudo stap -ve 'probe begin { log("hello world") exit() }'

2. 安装 debug 包

通过 uname -r 查看系统版本,到网站 http://debuginfo.centos.org/ 下载相应的软件包进行安装。

1
2
3
4
5
$wget http://debuginfo.centos.org/6/x86_64/kernel-debug-debuginfo-2.6.32-696.20.1.el6.x86_64.rpm
$wget http://debuginfo.centos.org/6/x86_64/kernel-debuginfo-2.6.32-696.20.1.el6.x86_64.rpm
$wget http://debuginfo.centos.org/6/x86_64/kernel-debuginfo-common-x86_64-2.6.32-696.20.1.el6.x86_64.rpm
$rpm -Uhv kernel-debuginfo-*.rpm
$rpm -Uhv kernel-debug-*.rpm

使用 yum 安装更方便

1
2
3
yum search kernel-debug
yum install -y kernel-debuginfo-common-x86_64.x86_64 kernel-debug.x86_64 kernel-debug-devel.x86_64 kernel-debuginfo.x86_64
debuginfo-install -y kernel-3.10.0-693.el7.x86_64

执行命令测试

1
2
3
4
[root@localhost ~]# stap -L 'kernel.function("printk")'
kernel.function("printk@kernel/printk.c:641") $fmt:char const* $args:va_list $r:int
[root@localhost ~]# stap -L 'process("/lib64/libc.so.6").function("malloc")'
process("/lib64/libc-2.12.so").function("malloc")

3. 下载火焰图生成工具

1
2
git clone https://github.com/brendangregg/FlameGraph.git
git clone https://github.com/openresty/openresty-systemtap-toolkit.git

二 NGINX 程序分析

1. NGINX 程序安装

使用 systemtap 分析 NGINX 非常方便, 正常编译安装进行测试并采集调用栈数据即可.

1
2
3
4
5
$sudo yum install gcc gcc-c++
$cd /opt/nginx-1.12.1
$./configure --with-http_dav_module --with-http_stub_status_module --add-module=/opt/nginx-1.12.1/src/dynamod/nginx_accept_language_module
$make
$make install

2. 采集 NGINX 数据

1
2
3
4
$cd /usr/local/nginx/sbin
$sudo ./nginx
$ps -ef|grep nginx # 查看进程 pid
$sudo stap --ldd -d /usr/local/nginx/module/ngx_http_du_entry_module.so -d /usr/local/nginx/sbin/nginx --all-modules -D MAXMAPENTRIES=10240 -D MAXACTION=20000 -D MAXSTRINGLEN=4096 -D MAXBACKTRACE=10240 -x 18421 ngx.stp --vp 0001 > ats.out

stap 参数:
x : 分析进程 pid
ldd : 指定分析的执行程序、动态模块
MAXACTION : 单个探针命中执行的最大次数
MAXSTRINGLEN : 字符串最大长度
MAXBACKTRACE : 栈展开的最大深度

3. 生成 NGINX 运行火焰图

1
2
3
4
5
# 下载火焰图项目代码
$git clone https://github.com/brendangregg/FlameGraph.git
# 使用 FlameGraph 项目脚本生成火焰图
$perl stackcollapse-stap.pl ats.out > ats.out2
$perl flamegraph.pl ats.out2 > ats.svg

将生成的 ats.svg 文件在浏览器打开就可以看到火焰图。

三 OpenResty 程序分析

如果不需要分析 lua 调用栈, 可以使用分析 NGINX 方法生成火焰图. 如果需要分析 lua 调用栈, 需要使用 OpenResty 社区的分析工具进行分析.

1. lj-lua-stacks 下载

1
git clone https://github.com/openresty/stapxx

2. OpenResty 编译

目前火焰图工具不支持 GC64 需要使用 --without-luajit-gc64 关闭 GC64 选项. 同时需要区分 OpenResty 版本是否默认启用 luajit, 可以使用 --with-luajit 开启.

1
2
3
4
5
$./configure --prefix=/usr/local \
--with-debug --with-pcre-jit --with-ipv6 \
--without-luajit-gc64 --with-luajit

$make && make install

3. 采集数据

1
2
3
4
5
6
$lj-lua-stacks.sxx -I ./stapxx/tapset -D MAXMAPENTRIES=102400 --arg time=10 --skip-badvars -x 1398924 > a.bt
# 下载火焰图项目代码
$git clone https://github.com/brendangregg/FlameGraph.git
# 使用 FlameGraph 项目脚本生成火焰图
$stackcollapse-stap.pl a.bt > a.cbt
$flamegraph.pl --encoding="ISO-8859-1" --title="Lua-land on-CPU flamegraph" a.cbt > a.svg

lj-lua-stacks 参数:

  • -I ./stapxx/tapset 指定 stap++ 依赖库目录.
  • -D MAXMAPENTRIES=102400 指定 stap 使用 map 的最大记录数.
  • --arg time=10 采集时间, 单位秒.
  • -x 1398924 Nginx Worker 进程号.

四 火焰图含义

  • y 轴表示调用栈,每一层都是一个函数。调用栈越深,火焰就越高,顶部就是正在执行的函数,下方都是它的父函数。
  • x 轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

火焰图就是看顶层的哪个函数占据的宽度最大。只要有”平顶”(plateaus),就表示该函数可能存在性能问题。颜色没有特殊含义,因为火焰图表示的是 CPU 的繁忙程度,所以一般选择暖色调。

五 参考资料