1、背景
OpenResty是网关、CDN和Waf等产品常用的底层解决方案,在国内外都有大量的使用者。在日常的使用过程中,难免会遇到性能问题。对于性能的问题,我们先要有工具可以观察和排查,才能深入到代码中解决问题,由于我们的业务逻辑大部分都是使用Lua代码实现的,仅仅靠系统级别的工具,比如perf,是观察不到Lua的代码热点在哪里。OpenResty作者春哥提供的了SystemTap脚本,可以用来定位Lua代码的热点。本文将从环境搭建,到代码编译,再到火焰图的输出,完整介绍如何查看Lua代码的火焰图。知名的开源网关ApiSix和Kong都是基于OpenResty之上二次开发,国内很多互联网企业的Waf也是基于OpenResty二次开发,可以说OpenResty的异步非阻塞模型的IO和网络,加上可以热重启Lua代码的机制,可以满足快速迭代、稳定和高性能的需求。
2、 环境搭建
需要提前安装好的工具:
- vagrant (管理虚拟机的工具,HashiCorp出品)
- virtualBox (虚拟机工具)
2.1 vagrant启动centos 7
Vagrantfile如下
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.box_url = "https://mirrors.ustc.edu.cn/centos-cloud/centos/7/vagrant/x86_64/images/CentOS-7.box"
config.vm.define "openresty"
config.vm.synced_folder "codes", "/codes"
config.vm.provider "virtualbox" do |v|
v.cpus = 4
v.memory = 2048
end
end
box_url指定了centos/7的下载地址,使用国内的源会快很多。另外synced_folder指定了Vagrantfile所在目录下的codes目录挂载到虚拟机的/codes目录中,这样方便本地开发电脑和虚拟机传输文件。
编辑完Vagrantfile后,执行vagrant up
就可以拉起一个虚拟机,启动过程中,可能因为挂载本地文件到虚拟机会有告警信息。如果遇到以下问题,可以参考:
-
如果启动虚拟机报错:
mount: unknown filesystem type 'vboxsf'
解决方案: vagrant plugin install vagrant-vbguest
-
本地文件不能同步到Centos 7虚拟机的问题解决
-
vagrant ssh 登录到虚拟机内部
-
sudo yum -y install epel-release
-
sudo yum -y update
-
sudo yum install make gcc kernel-headers kernel-devel perl dkms bzip2 -y
-
随后执行退出虚拟机执行vagrant reload即可
-
登录机器后,就可以看到挂载点的文件。1这个文件在本地可以编辑
[vagrant@localhost codes]$ ls 1
-
当一切的问题解决后,就可以使用vagrant ssh
登录到机器中,愉快的使用虚拟机了。
2.2 systemtap工具安装
- systemtap安装:
sudo yum install -y systemtap
, 安装完后,还不能直接使用,因此systemtap依赖于内核的debuginfo,因此我们还需要安装内部的debuginfo。 - 安装debuginfo,由于Centos默认是没有激活debug info的安装库,需要在我们安装的时候指定库:
sudo yum --enablerepo=base-debuginfo install -y kernel-debuginfo-$(uname -r)
安装成功后,可以使用sudo stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
检查前面两个安装步骤是否没问题。
-
切换到本地开发机器上,使用git下载三个工具,用于生产Lua代码的火焰图
- stapxx ,用于获取Lua的运行信息:
git clone https://github.com/yxudong/stapxx.git
, 不是用春哥的文档中的stapxx,是因为他开源的版本不支持gcc 64 bit mode - openresty官方提供的systemtap脚本:
git clone https://github.com/openresty/openresty-systemtap-toolkit.git
- 火焰图生成工具:
git clone https://github.com/brendangregg/FlameGraph.git
- stapxx ,用于获取Lua的运行信息:
2.3 openresty的编译和运行
虚拟机和systemtap的工具都安装好了,是时候开始编译openresty和运行demo了。我们下载一个2022年5月18日发布的最新版本的openresty,看一下效果:
-
下载最新源码: wget openresty.org/download/op…
-
解压:
tar -xf openresty-1.21.4.1.tar.gz
-
安装编译依赖工具 :
yum install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel -y
-
切换到源码目录,执行编译三部曲
./configure
make -j4
,cpu的个数是4个- 安装到机器中
sudo make install
-
检查安装是否成功:
sudo /usr/local/openresty/bin/openresty -v
,输出nginx version: openresty/1.21.4.1
-
在/etc/bashrc 中加入openresty的路径到PATH中
PATH=/usr/local/openresty/nginx/sbin:$PATH export PATH
2.3.1 demo
在demo的目录中,创建配置文件和日志的目录:mkdir -p logs conf
。接着配置文件conf/nginx.conf 编辑内容如下
worker_processes auto;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
default_type text/html;
content_by_lua_block {
ngx.say("<p>hello, world</p>")
}
}
}
}
启动nginx的时候,需要切换到root权限(也不一定需要root,关键是因为pid和端口的问题,需要root就方便很多,demo就不再展开权限相关的问题),统一切换到root用户: sudo su
后执行。
启动openresty
nginx -p
pwd
/ -c conf/nginx.con
启动后,没有任何输出,这个是正常的。Linux的哲学就是 :没报错信息,就是运行正常
接着,我们访问一下本地的8080端口,返回一切正常
[root@localhost vagrant]# curl http://127.0.0.1:8080
hello, world
2.3.2 火焰图生成
conf/nginx.conf文件修改一下,重新reload一下nginx
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
default_type text/html;
content_by_lua_block {
local sha1 = require "resty.sha1"
local to_hex = require "resty.string".to_hex
for i = 10,1,-1
do
local digest = sha1:new()
digest:update("some")
to_hex(digest:final())
end
ngx.say("<p>hello, world</p>")
}
}
}
}
使用ab进行压测:ab -c 10 -n 100000000 http://127.0.0.1:8080/
,压测启动后,再进行采样,采样这里需要注意,CPU有压力才能采样到数据,所以才需要进行压测。步骤:
- 切换stapxx目录:
cd /codes/stapxx
- 当前路径在到PATH中:
export PATH=$PWD:$PATH
-
采样:
./samples/lj-lua-stacks.sxx --arg time=5 --skip-badvars -x 28183 > tmp.bt
,其中-x指定的是nginx worker的PID。 -
使用openresty-system-toolkit工具,调整一下tmp.bt的采样结果:
- cd /codes/openresty-systemtap-toolkit/
- ./fix-lua-bt ../stapxx/tmp.bt > flame.bt
- mv flame.bt /codes/FlameGraph/
-
切换到火焰图生成工具目录,开始生成火焰图
- cd /codes/FlameGraph
- ./stackcollapse-stap.pl flame.bt |./flamegraph.pl > flame.svg
-
本地电脑浏览器查看火焰图
可以看出,to_hex的函数是主要的性能热点。
总结:
本文仅提供了一个Demo,用来指导如何从环境安装到编译,再到例子Demo,一步步的生成火焰图。在真实的业务场景中,会更加复杂,但是万变不离其宗,这个Demo应该足以入门如何查看OpenResty的Lua代码火焰图。