php opcache 坑,PHP-FPM占用CPU过高分析及OPcache解决

平时站点CPU使用率都在10%以内,最近发现达到了50%左右

top查看服务器资源使用情况:

%Cpu0 : 41.9 us, 1.3 sy, 0.0 ni, 56.1 id, 0.3 wa, 0.0 hi, 0.3 si, 0.0 st

KiB Mem : 1016164 total, 68120 free, 583512 used, 364532 buff/cache

KiB Swap: 0 total, 0 free, 0 used. 251176 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

5705 www 20 0 281272 40360 4516 S 15.0 4.0 0:09.09 php-fpm

5704 www 20 0 281292 40604 4584 S 8.0 4.0 0:08.89 php-fpm

5706 www 20 0 281124 41124 5296 S 8.0 4.0 0:08.80 php-fpm

5707 www 20 0 281328 40596 4580 S 7.7 4.0 0:08.77 php-fpm

分析top的结果,我们可以看出是FPM占用了过多的CPU资源。那么问题就清晰了:FPM为什么占用了这么多CPU资源,如何分析,如何解决?

带着这些问题,思考&解决思路整理如下:

0、查看nginx error和php-fpm slowlog, 排除应用本身的明显异常问题。

1、查看PHP是否开启OPcache缓存。

OPcache通过将PHP脚本预编译的字节码存储到共享内存中来提升PHP的性能,存储预编译字节码的好处就是省去了每次加载和解析PHP脚本的开销。

在phpinfo中或者php.ini中查看是否开启了OPcache,如果没有开启之。

官方建议php.ini中关于opcache的设置如下,更多参数参考这里:

[opcache]

zend_extension=/usr/local/php/lib/php/extensions/no-debug-zts-20170718/opcache.so

; OPcache打开/关闭开关。当设置为Off或者0时,会关闭Opcache, 代码没有被优化和缓存。

opcache.enable=1

; OPcache共享内存存储大小。用于存储预编译的opcode(以MB为单位)。

opcache.memory_consumption=64

; 用来存储临时字符串的内存大小,以兆字节为单位.

opcache.interned_strings_buffer=8

; 这个选项用于控制内存中最多可以缓存多少个PHP文件。

opcache.max_accelerated_files=4000

; 从缓存不被访问后,等待多久后(单位为秒)调度重启.

opcache.force_restart_timeout=180

; 这个选项用于设置缓存的过期时间(单位是秒),当这个时间达到后,opcache会检查你的代码是否改变,如果改变了PHP会重新编译它,生成新的opcode,并且更新缓存。

opcache.revalidate_freq=60

;如果启用,则会使用快速停止续发事件。 所谓快速停止续发事件是指依赖 Zend 引擎的内存管理模块 一次释放全部请求变量的内存,而不是依次释放每一个已分配的内存块。

opcache.fast_shutdown=1

; CLI环境下,PHP启用OPcache。这主要是为了测试和调试。从 PHP 7.1.2 开始,默认启用。

opcache.enable_cli=1

生产环境实际值参考(6C CPU,16G内存,300G硬盘):

opcache.memory_consumption=128

opcache.interned_strings_buffer=8

opcache.max_accelerated_files=4000

opcache.revalidate_freq=1

opcache.fast_shutdown=1

opcache.enable_cli=1

opcache.save_comments=0

opcache.enable_file_override=1

我这里的原因就是没有开启Opcache,开启后的top结果如下,可以看到效果很明显:

%Cpu(s): 7.7 us, 0.3 sy, 0.0 ni, 91.3 id, 0.7 wa, 0.0 hi, 0.0 si, 0.0 st

KiB Mem : 1016164 total, 160036 free, 498056 used, 358072 buff/cache

KiB Swap: 0 total, 0 free, 0 used. 317092 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

5815 www 20 0 328876 34644 19648 S 2.3 3.4 0:00.59 php-fpm

5816 www 20 0 328856 29796 14644 S 1.7 2.9 0:00.46 php-fpm

5817 www 20 0 328856 27304 13188 S 1.3 2.7 0:00.45 php-fpm

5818 www 20 0 328856 36976 22816 S 1.3 3.6 0:00.93 php-fpm

2、strace工具调试一下看瓶颈在哪里。(strace一篇比较友好的入门介绍参考这里)

比如使用某些框架,需要动态的打开文件,框架是否支持优化的方案,到框架的官网上去看下,一般都有,另外框架一般默认加载了大而全的东西,检查下如果不是需要的是否可不加载。

[root@izj6cfhaw27k49x8usszs3z ~]# strace -c -p 5818

strace: Process 5818 attached

^Cstrace: Process 5818 detached

% time seconds usecs/call calls errors syscall

------ ----------- ----------- --------- --------- ----------------

33.14 0.000056 2 24 sendto

28.40 0.000048 1 50 poll

17.75 0.000030 1 50 recvfrom

9.47 0.000016 8 2 setsockopt

6.51 0.000011 0 78 read

1.78 0.000003 0 11 10 lstat

0.59 0.000001 0 5 open

0.59 0.000001 0 11 close

0.59 0.000001 0 31 access

0.59 0.000001 0 8 getdents

0.59 0.000001 0 4 openat

0.00 0.000000 0 1 write

0.00 0.000000 0 12 stat

0.00 0.000000 0 5 fstat

0.00 0.000000 0 13 lseek

0.00 0.000000 0 8 rt_sigaction

0.00 0.000000 0 1 rt_sigprocmask

0.00 0.000000 0 4 setitimer

0.00 0.000000 0 1 socket

0.00 0.000000 0 1 1 connect

0.00 0.000000 0 1 accept

0.00 0.000000 0 1 shutdown

0.00 0.000000 0 1 getsockopt

0.00 0.000000 0 5 fcntl

0.00 0.000000 0 2 times

------ ----------- ----------- --------- --------- ----------------

100.00 0.000169 330 11 total

从上图可以看到耗时最长的是sendto操作,可以单独跟踪下sendto操作

[root@izj6cfhaw27k49x8usszs3z ~]# strace -T -e sendto -p 5818

strace: Process 5818 attached

sendto(5, "S\0\0\1\215\242\n\0\0\0\0\300!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 87, MSG_DONTWAIT, NULL, 0) = 87 <0.000017>

sendto(5, "\22\0\0\0\3SET NAMES utf8mb4", 22, MSG_DONTWAIT, NULL, 0) = 22 <0.000011>

sendto(5, "5\0\0\0\3SET NAMES 'utf8mb4' COLLATE"..., 57, MSG_DONTWAIT, NULL, 0) = 57 <0.000010>

sendto(5, "\32\0\0\0\3SELECT @@SESSION.sql_mode", 30, MSG_DONTWAIT, NULL, 0) = 30 <0.000011>

sendto(5, ".\0\0\0\3SET SESSION sql_mode='NO_EN"..., 50, MSG_DONTWAIT, NULL, 0) = 50 <0.000009>

sendto(5, "\6\0\0\0\2niliu", 10, MSG_DONTWAIT, NULL, 0) = 10 <0.000011>

sendto(5, "H\0\0\0\3SELECT option_name, option_"..., 76, MSG_DONTWAIT, NULL, 0) = 76 <0.000018>

sendto(5, "Y\0\0\0\3SELECT option_value FROM wp"..., 93, MSG_DONTWAIT, NULL, 0) = 93 <0.000025>

sendto(5, "N\0\0\0\3SELECT option_value FROM wp"..., 82, MSG_DONTWAIT, NULL, 0) = 82 <0.000022>

可以看到没有很明显的异常

3、尝试优化业务,DB之前尽量增加Cache。

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值