服务上云后如何使用 perf 生成火焰图

业务上云迁移至腾讯云 Serverless 集群后,使用perf生成服务器的火焰图。

背景

业务模块使用的基础镜像是Ubuntu20.04,上云前的做法是在机器上docker run的,命令如下:

docker run --cap-add CAP_SYS_ADMIN --privileged=true --pid=container:${targetContainerId} --network=container:${targetContainerId} ${image}:${imageTag} -ti ...

上云后通过在 Pod 中的容器之间共享进程命名空间的方式实现,在业务Pod中注入一个用于perf分析的容器。

安装 perf

apt-get install linux-tools-generic
ln -s /usr/lib/linux-tools/5.4.0-125-generic/perf /usr/bin/perf

注意事项
安装 linux-tools-generic 完成后,需要建立软链接,不然查看 perf版本,会提示如下报错信息。

root@game-server-6-6f446dcxxx-5j45b:~# perf
WARNING: perf not found for kernel 5.4.119-1

You may need to install the following packages for this specific kernel:
linux-tools-5.4.119-1-tlinux4-0009-public-eks
linux-cloud-tools-5.4.119-1-tlinux4-0009-public-eks

You may also want to install one of the following packages to keep up to date:
linux-tools-tlinux4-0009-public-eks
linux-cloud-tools-tlinux4-0009-public-eks

这里报错其实是因为perf已经内置在linux-tools-generic里面,所以我们安装后创建perf软链接即可(5.4.0-125-generic 版本目录根据实际情况替换即可)。

使用 perf 生成火焰图

pod 共享进程命名空间

使用 Pod .spec 中的 shareProcessNamespace 字段可以启用进程命名空间共享,官方例子:

apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
shareProcessNamespace: true
containers:
- name: nginx
image: nginx
- name: shell
image: busybox:1.28
securityContext:
capabilities:
add:
- SYS_PTRACE
privileged: true
stdin: true
tty: true

注意事项
我们需要在 perf 容器中分析业务容器 gamesvr,这个操作需要 SYS_PTRACE 权能。所以我们需要为 perf Container 设置权能。通过安全上下文(Security Context)定义 Pod 或 Container 的特权与访问控制设置。

这里列举部分能力:

CAP_SYS_MODULE: 允许插入和删除内核模块
CAP_SYS_RAWIO: 允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备
CAP_SYS_CHROOT: 允许使用chroot()系统调用
CAP_SYS_PTRACE: 允许跟踪任何进程
CAP_SYS_PACCT: 允许执行进程的BSD式审计

我们使用 perf来分析业务进程,所以需要 CAP_SYS_PTRACE 权能。

Linux Capabilities 的定义的形式为 CAP_XXX。但是你在 Container 字段使用时,需要将名称中的 CAP_ 部分去掉。例如,要添加 CAP_SYS_PTRACE,可在 capabilities 列表中添加 SYS_PTRACE。

perf 容器注入

我这里工作负载是使用的 deployment,通过 openkruise sidecarset 注入,这里就不赘述。注入完成后我们 exec 进入 perf 容器,执行 ps -ef 可以看到业务容器的进程 gamesvr 的进程ID是13。

root@game-server-6-6f446dcxxx-5j45b:~# ps -ef 
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 19:29 ? 00:00:00 /pause
root 13 0 6 19:29 ? 00:02:37 /root/example/bin/gamesvr
root 26 0 0 19:29 ? 00:00:00 sleep 9d
root 786 0 0 20:02 pts/0 00:00:00 /bin/bash
root 855 842 0 20:11 pts/1 00:00:00 ps -ef

perf 分析

执行 perf record -F 99 -g -m 1 -p ${targetContainerId} -- sleep 120,targetContainerId 是业务进程ID。

root@game-server-6-6f446dcxxx-5j45b:~# perf record -F 99 -g -m 1 -p 13 -- sleep 120
[ perf record: Woken up 65 times to write data ]
[ perf record: Captured and wrote 0.148 MB perf.data (524 samples) ]

查看分析文件

root@game-server-6-6f446dcxxx-5j45b:~# perf report -i perf.data > perf.txt

生成火焰图,这里会用到火焰图工具

root@game-server-6-6f446dcxxx-5j45b:~# git clone https://github.com/brendangregg/FlameGraph.git
root@game-server-6-6f446dcxxx-5j45b:~# perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > demo.svg

这里生成的 demo.svg 就是我们需要的火焰图(下面是一个例图)。开发可以通过火焰图来查看看服务的性能热点。

总结

这里协助开发使用 perf 生成火焰图的过程中遇到了2个问题,一是安装 perf 装不上报错,二是由于 perf 容器没有 SYS_PTRACE 权能导致生成的分析数据没有函数名称(只有地址信息)。通过协助排查问题加深了对 k8s Security Context的理解。

参考文档