记一次Web服务器lstat系统调用严重故障分析

    先看下系统环境
       Centos6.5 x64
       Tengine-2.1.0
       PHP-5.5.30
    随着业务流量增加,根据监控发现系统%sys的CPU占用率一度超过40%~50%(业务高峰期更为严重),
由于系统跑的是PHP,Nginx服务没有其它额外服务,PHP又容易成为系统的瓶颈,故使用strace跟踪了php-fpm进程的调用,如图:

看现象

通过top命令查看实时状态,%sys内核态CPU占比非常高,负载较高

通过strace跟踪php-fpm进程运行时的系统调用 strace -c -p $(pgrep -n php-fpm)

lstat调用到底干什么的呢?manlstat
manlstatte

分析问题

根据上面的现象可以看到lstat调用占用绝大部份的内核态CPU时间,可以通过strace跟踪php-fpm详细的lstat调用规律
strace  -o strace.out -r -s 256 $(pgrep -n php-fpm)

    由上面的信息不难看到程序在使用include,require,require_once,include_once,fopen,gzopen等开启了open_basedir之后,lstat调用会递归访问的文件目录查看文件位置限制,文件在open_basedir指定的目录以外时将拒绝打开,所有符号链接也会被解析无法避免此限制 ,这样就导致了lstat()调用比不开启open_basedir调用频率高很多;另外include,require,require_once,include_once在包含相对路径时,如果代码中存在大量的这样的语句,每次都从include_path中查找相应的文件,也会造成性能问题,所以通常用 realpath_cache_size 和realpath_cache_ttl来对文件的realpath进行缓存,但是开启了open_basedir之后,这个缓存是失效的;查看了官方的bug:https://bugs.php.net/bug.php?id=52312 有记录并没有修复,估计是考虑到安全问题

验证问题

大概了解了问题原因之后,对症下药来做测试,按三种情况测试下性能:
1.开启open_basedir

2.使用realpath_turbo进行优化,开启open_basedir时,依然可以使用realpath cache;
安装realpath_turbo扩展https://github.com/Whissi/realpath_turbo,修改php.ini

注意事项:使用realpath_turbo时,要关闭创建和操作符号链接的函数,否则会绕过 open_basedir安全限制,但依然不推荐在多虚拟主机环境使用
3.关闭open_basedir,增加realpath缓存

写脚本分别采集三种环境下系统调用占CPU时间百分比(采集半小时)

最终性能对比结果如图(横轴为采样id(s),纵轴为%sys占CPU时间比):

tongji

结论

  为了性能暂时关闭了open_basedir参数,开启realpath cache缓存,代码尽量少用include,require,include_once,require_once等

记一次Web服务器lstat系统调用严重故障分析》上有1条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注