14.性能优化答疑二

一、使用perf 工具,看到的是十六进制地址而不是函数名。

查看perf最后欧,就会看到警告信息:

Failed to open /opt/bitnami/php/lib/php/extensions/opcache.so, continuing without symbols

这说明,perf 找不到待分析进程依赖的库。当然,实际上这个案例中有很多依赖库都找不到,只不过,perf 工具本身只在最后一行显示警告信息,所以你只能看到这一条警告。

这个问题,其实也是在分析 Docker 容器应用时,我们经常碰到的一个问题,因为容器应用依赖的库都在镜像里面。

针对这种情况,我总结了下面四个解决方法。

第一个方法,在容器外面构建相同路径的依赖库。这种方法从原理上可行,但是我并不推荐,一方面是因为找出这些依赖库比较麻烦,更重要的是,构建这些路径,会污染容器主机的环境。

第二个方法,在容器内部运行 perf。不过,这需要容器运行在特权模式下,但实际的应用程序往往只以普通容器的方式运行。所以,容器内部一般没有权限执行 perf 分析。

比方说,如果你在普通容器内部运行 perf record ,你将会看到下面这个错误提示:

$ perf_4.9 record -a -g
perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error 1 (Operation not permitted)
perf_event_open(..., 0) failed unexpectedly with error 1 (Operation not permitted)

当然,其实你还可以通过配置 /proc/sys/kernel/perf_event_paranoid (比如改成 -1),来允许非特权用户执行 perf 事件分析。

不过还是那句话,为了安全起见,这种方法我也不推荐。

第三个方法,指定符号路径为容器文件系统的路径。比如对于第 05 讲的应用,你可以执行下面这个命令:

$ mkdir /tmp/foo
$ PID=$(docker inspect --format {{.State.Pid}} phpfpm)
$ bindfs /proc/$PID/root /tmp/foo
$ perf report --symfs /tmp/foo

# 使用完成后不要忘记解除绑定
$ umount /tmp/foo/

不过这里要注意,bindfs 这个工具需要你额外安装。bindfs 的基本功能是实现目录绑定(类似于 mount --bind),这里需要你安装的是 1.13.10 版本(这也是它的最新发布版)。

如果你安装的是旧版本,你可以到 GitHub上面下载源码,然后编译安装。

第四个方法,在容器外面把分析纪录保存下来,再去容器里查看结果。这样,库和符号的路径也就都对了。

比如,你可以这么做。先运行 perf record -g -p < pid>,执行一会儿(比如 15 秒)后,按 Ctrl+C 停止。

然后,把生成的 perf.data 文件,拷贝到容器里面来分析:

$ docker cp perf.data phpfpm:/tmp 
$ docker exec -i -t phpfpm bash

接下来,在容器的 bash 中继续运行下面的命令,安装 perf 并使用 perf report 查看报告:

$ cd /tmp/ 
$ apt-get update && apt-get install -y linux-tools linux-perf procps
$ perf_4.9 report

不过,这里也有两点需要你注意。

首先是 perf 工具的版本问题。在最后一步中,我们运行的工具是容器内部安装的版本 perf_4.9,而不是普通的 perf 命令。这是因为, perf 命令实际上是一个软连接,会跟内核的版本进行匹配,但镜像里安装的 perf 版本跟虚拟机的内核版本有可能并不一致。

另外,php-fpm 镜像是基于 Debian 系统的,所以安装 perf 工具的命令,跟 Ubuntu 也并不完全一样。比如, Ubuntu 上的安装方法是下面这样:

$ apt-get install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r))

而在 php-fpm 容器里,你应该执行下面的命令来安装 perf:

$ apt-get install -y linux-perf

当你按照前面这几种方法操作后,你就可以在容器内部看到 sqrt 的堆栈:

 二、使用perf工具分析Java

两个问题,其实是上一个 perf 问题的延伸。 像是 Java 这种通过 JVM 来运行的应用程序,运行堆栈用的都是 JVM 内置的函数和堆栈管理。所以,从系统层面你只能看到 JVM 的函数堆栈,而不能直接得到 Java 应用程序的堆栈。

perf_events 实际上已经支持了 JIT,但还需要一个 /tmp/perf-PID.map 文件,来进行符号翻译。当然,开源项目 perf-map-agent 可以帮你生成这个符号表。

此外,为了生成全部调用栈,你还需要开启 JDK 的选项 -XX:+PreserveFramePointer。因为这里涉及到大量的 Java 知识,我就不再详细展开了。如果你的应用刚好基于 Java ,那么你可以参考 NETFLIX 的技术博客 Java in Flames (链接为 https://medium.com/netflix-techblog/java-in-flames-e763b3d32166),来查看详细的使用步骤。

说到这里,我也想强调一个问题,那就是学习性能优化时,不要一开始就把自己限定在具体的某个编程语言或者性能工具中,纠结于语言或工具的细节出不来。

掌握整体的分析思路,才是我们首先要做的。因为,性能优化的原理和思路,在任何编程语言中都是相通的。

三、为什么 perf 的报告中,很多符号都不显示调用栈

perf record -g 命令手机信息,收集多次,每次都是command列为swapper的左侧有加号,而app或其他的没有加号,在symbol列看到sys_read,new_sync_read,blkdev_read_iter等信息。(Ubunt系统)。

perf report是可视化展示perf.data工具,在运行时,看到以下界面:

清楚看到只有swapper调用栈,其他所有符号都不能看到堆栈。发现性能工具无法理解时查看手册,man perf-report,找到 -g 说明:

通过这个说明可以看到,-g 选项等同于 --call-graph,它的参数是后面那些被逗号隔开的选项,意思分别是输出类型、最小阈值、输出限制、排序方法、排序关键词、分支以及值的类型。

我们可以看到,这里默认的参数是 graph,0.5,caller,function,percent,具体含义文档中都有详细讲解,这里我就不再重复了。

现在再回过头来看我们的问题,堆栈显示不全,相关的参数当然就是最小阈值 threshold。通过手册中对 threshold 的说明,我们知道,当一个事件发生比例高于这个阈值时,它的调用栈才会显示出来。

threshold 的默认值为 0.5%,也就是说,事件比例超过 0.5% 时,调用栈才能被显示。再观察我们案例应用 app 的事件比例,只有 0.34%,低于 0.5%,所以看不到 app 的调用栈就很正常了。

这种情况下,你只需要给 perf report 设置一个小于 0.34% 的阈值,就可以显示我们想看到的调用图了。比如执行下面的命令:

$ perf report -g graph,0.3

你就可以得到下面这个新的输出界面,展开 app 后,就可以看到它的调用栈了。

 

四、perf report 报告。

 在perf展开的分析详情中,有children和self都有90%多的swapper进程,进而去围绕这个进程展开,忽略只占用0.6%的app进程?

      看到swapper,先想到的是SWAP分区,swapper跟SWAP没有任何关系,它只是系统初始化时  的init进程,之后就成了一个最低优先级空闲任务。当CPU上没有任何任务运行时,就会执行swapper,被称为“空闲任务”。

在perf report界面中,展开它的调用栈,看到swapper时钟事件都消耗费在了do_idle上,也就是在执行空闲任务:

所以,分析图,直接忽略前面99%的符号,转而分析后面只有0.3%的app。其实在多任务系统中,次数的事件,不一定就是性能瓶颈。

所以在只观察一个大数值,并不能说明什么问题,具体有没有瓶颈还要观测多个方面的多个指标,交叉验证。

另外,关于Children和Self的含义,手册有详细说明:

  • Self 是最后一列的符号(可以理解为函数)本身所占比例;
  • Children 是这个符号调用的其他符号(理解为子函数,包括直接调用和间接调用)占用的比列之和。

perf,需要在内核中跟踪内核栈的各种事件,不可避免带来一定的性能损失,虽然对大部分应用没有太大影响,但特定某些应用(像对时钟周期特别敏感的应用),可能就是灾难。

在使用性能工具时,要考虑工具本身对系统的影响,就要了解工具的原理:

  • perf 这种动态追踪工具,会带来性能损失。
  • vmstat、pidstat这些直接读取proc 文件的系统来获取指标的工具,不会带来性能损失。 

 五、性能优化书籍和参考资料推荐。

Brendan Gregg 是一位当之无愧的性能优化大师,他的性能工具图谱很多文章中都会看到:Linux性能篇一

Brendan Gregg 的性能优化书籍《Systems Performance:Enterprise and the Cloud》。中文版的名字是:《性能之巅:洞悉系统、企业与云计算》。虽然在2013年出版,但依然是经典,分析思路鸡性能工具依然适合现在。

Brendan Gregg 的个人网站:http://www.brendangregg.com/  ,特别是 Linux Performance 这一页包含很多Linux性能优化资料,比如:

  • Linux性能工具图谱
  • 性能分析参考资料
  • 性能优化演讲视频

但很多内容涉及到内核知识,对于初学者不太友好,要循序渐进一遍遍阅读。 

猜你喜欢

转载自www.cnblogs.com/LHXW/p/10170336.html
今日推荐