昨天《如何衡量单机PHP支撑能力》提到了OPcache,今天在自己的ECS上做了些测试,结果令人激动。
什么是Opcache
即使不使用OPcache,PHP7的性能也是非常高的。PHP脚本每次运行的时候,都要动态解析PHP代码,然后再执行。
如果将解析的结果保存下来,这样执行的时候就省去了解析,执行的性能就会提升。
将代码解析结果保存到共享内存中,这就是OPcache,PHP-FPM worker进程都能使用该内存区域。
如何启用OPcache
PHP5.6以上的版本默认编译了OPcache,不过要真正启用,必须在php.ini中配置 zend_extension=opcache.so,动态加载 Zend extension。
如果php -v 出现with Zend OPcache v7.2.8, Copyright (c) 1999-2018, by Zend Technologies,说明启用了OPcache。
如何配置OPcache
具体见 www.php.net/manual/zh/opcache.configuration.php,说几个有用的。
opcache.enable 表示启用OPcache。
opcache.enable_cli 表示PHP命令行也启用OPcache。
opcache.memory_consumption 表示共享内存的大小。
opcache.interned_strings_buffer PHP相同字符串可以保存到共享内存中。
opcache.validate_timestamps 如果是1表示每次都会检查PHP文件的更新时间,以便确定是否使用OPcache,在生产环境中建议关闭,这样性能更高,那如果源文件修改了怎么办?后面会说。
opcache.max_accelerated_files 表示可缓存文件的最大个数。
opcache.enable_file_override 如果开启,则在调用函数 file_exists(),is_file() 以及 is_readable() 的时候,都会检查OPcache。
opcache.file_cache 可以将OPcache导出到外部文件,这样即使重启PHP,外部文件的OPcache也能使用,但自己没有开启。
如何运用在生产环境
OPcache确实很好,但如果opcache.validate_timestamps关闭,那么源文件如果变更,如何能够更新OPcache呢?
有两种方法,第一个就是重启PHP-FPM,第二个就是调用 opcache_reset() 函数。
重启PHP-FPM不太适合,比如在QA环境,不能修改一行代码就启动PHP-FPM,所以目前的方法就是QA代码(if/else)使用opcache_reset()强制不使用OPcache。
那么生产环境如何更新OPcache呢?目前的方法就是在ssh git分发代码的时候,增加curl一个接口,该接口就是执行opcache_reset()。
OPcache统计
内置opcache_get_status()函数可以了解统计数据,比如:
[memory_usage] => Array ( [used_memory] => 21200864 [free_memory] => 113016864 [wasted_memory] => 0 [current_wasted_percentage] => 0 ) [interned_strings_usage] => Array ( [buffer_size] => 8388608 [used_memory] => 710928 [free_memory] => 7677680 [number_of_strings] => 16899 ) [opcache_statistics] => Array ( [num_cached_scripts] => 36 [num_cached_keys] => 44 [max_cached_keys] => 16229 [hits] => 36 [start_time] => 1591457444 [last_restart_time] => 1591457446 [oom_restarts] => 0 [hash_restarts] => 0 [manual_restarts] => 1 [misses] => 36 [blacklist_misses] => 0 [blacklist_miss_ratio] => 0 [opcache_hit_rate] => 50 ) [scripts] => Array
free_memory 表示共享内存还有多少没有用;current_wasted_percentage表示浪费的内存,达到一定比例,会自动清除OPcache;opcache_hit_rate表示OPcache命中率;scripts 表示查看那些脚本被缓存了。
具体效果
使用ab进行并发测试。
yum -y install httpd-tools ab -n 10000 -c 500 url #并发500
在开启OPcache的时候:
Concurrency Level: 500 Time taken for tests: 38.155 seconds Complete requests: 10000 Failed requests: 340 (Connect: 0, Receive: 0, Length: 340, Exceptions: 0) Write errors: 0 Non-2xx responses: 340 Total transferred: 1938420 bytes HTML transferred: 564000 bytes Requests per second: 262.09 [#/sec] (mean) Time per request: 1907.740 [ms] (mean) Time per request: 3.815 [ms] (mean, across all concurrent requests) Transfer rate: 49.61 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 14 510 1156.1 25 15056 Processing: 19 398 1557.7 32 29043 Waiting: 19 398 1557.7 32 29043 Total: 33 908 2014.5 269 32053
没有开启的情况下:
Concurrency Level: 500 Time taken for tests: 28.447 seconds Complete requests: 10000 Failed requests: 7663 (Connect: 0, Receive: 0, Length: 7663, Exceptions: 0) Write errors: 0 Non-2xx responses: 10000 Total transferred: 2784615 bytes HTML transferred: 1270593 bytes Requests per second: 351.53 [#/sec] (mean) Time per request: 1422.361 [ms] (mean) Time per request: 2.845 [ms] (mean, across all concurrent requests) Transfer rate: 95.59 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 14 326 1302.2 23 15060 Processing: 14 1035 1884.1 27 9045 Waiting: 14 1035 1884.1 27 9045 Total: 29 1361 2246.7 58 21169
有的同学很奇怪,怎么开启OPcache的情况下,执行时间反而更长?原因在于并发数太高,而单请求响应时间长,PHP-FPM worker子进程达到了500;而开启OPcache的时候,执行效率高,worker进程没有超过20,所以其总体时间更长。
另外如果没有开启OPcache,则CPU负载瞬间飙到10以上;而开启OPcache的话,CPU负载没有超过1。
转载请注明:爱学习爱分享 » OPcache:提升 PHP 性能的利器