Opcode是啥以及如何使用好Opcache

转载  https://www.zybuluo.com/phper/note/1016714php

 

啥是Opcode?

咱们在平常的PHP开发过程当中,应该常常会听见Opcache这个词,那么啥是Opcode呢?nginx

Opcache 的前生是 Optimizer+ ,它是PHP的官方公司 Zend 开发的一款闭源但能够无偿使用的 PHP 优化加速组件。 Optimizer+ 将PHP代码预编译生成的脚本文件 Opcode 缓存在共享内存中供之后反复使用,从而避免了从磁盘读取代码再次编译的时间消耗。同时,它还应用了一些代码优化模式,使得代码执行更快。从而加速PHP的执行。git

Optimizer+ 于 2013年3月中旬更名为 Opcache。而且在 PHP License 下开源: https://github.com/zendtech/ZendOptimizerPlusgithub

Opcache的生命周期

了解了啥是Opcache以及Opcache的做用。如今看一下Opcache的运行图。web

正常的php代码的执行过程以下:redis

request请求(nginx,apache,cli等)-->Zend引擎读取.php文件-->扫描其词典和表达式 -->解析文件-->建立要执行的计算机代码(称为Opcode)-->最后执行Opcode--> response 返回apache

每一次请求PHP脚本都会执行一遍以上步骤,若是PHP源代码没有变化,那么Opcode也不会变化,显然没有必要每次都重行生成Opcode,结合在Web中无所不在的缓存机制,咱们能够把Opcode缓存下来,之后直接访问缓存的Opcode岂不是更快,启用Opcode缓存以后的流程图以下所示:json

request请求(nginx,apache,cli等)-->Zend引擎读取.php文件-->读取Opcode-->执行Opcode--> response 返回数组

Opcache的安装

实际上,在php5.5之后,Opcache 是默认安装好了的,已经不须要咱们再手动去安装了,可是默认是没有开启的,若是咱们须要使用,须要手动去开启:浏览器

  1. zend_extension=opcache.so
  2. [opcache]
  3. opcache.enable=1 #容许在web环境使用,默认是开启的。
  4. opcache.enable_cli=1 #运行在cli环境使用

重启 fpm 和 nginx

  1. kill -USR2 cat `/usr/local/php/var/run/php-fpm.pid`
  2. nginx -s reload

这样就可使用opcache了。

推荐的 php.ini 中 Opcache的配置

如下是官网推荐的php.ini中的配置。能够在生产环境得到更高的性能:

  1. opcache.enable=1
  2. opcache.memory_consumption=128
  3. opcache.interned_strings_buffer=8
  4. opcache.max_accelerated_files=4000
  5. opcache.revalidate_freq=60
  6. opcache.fast_shutdown=1 ;(在PHP 7.2.0中被移除,会自动开启)
  7. opcache.enable_cli=1

opcache的配置说明。

上面是官方推荐的一些配置,其实它还有一大长条的配置,咱们选择几个重要的,会被使用到的,来讲下他们的具体含义:

  1. opcache.enable=1 (default "1")
  2. ;OPcache打开/关闭开关。当设置为Off或者0时,会关闭Opcache, 代码没有被优化和缓存。
  3. opcache.enable_cli=1 (default "0")
  4. ;CLI环境下,PHP启用OPcache。这主要是为了测试和调试。从 PHP 7.1.2 开始,默认启用。
  5. opcache.memory_consumption=128 (default "64")
  6. ;OPcache共享内存存储大小。用于存储预编译的opcode(以MB为单位)。
  7. opcache.interned_strings_buffer=8 (default "4")
  8. ;这是一个颇有用的选项,可是彷佛彻底没有文档说明。PHP使用了一种叫作字符串驻留(string interning)的技术来改善性能。例如,若是你在代码中使用了1000次字符串“foobar”,在PHP内部只会在第一使用这个字符串的时候分配一个不可变的内存区域来存储这个字符串,其余的999次使用都会直接指向这个内存区域。这个选项则会把这个特性提高一个层次——默认状况下这个不可变的内存区域只会存在于单个php-fpm的进程中,若是设置了这个选项,那么它将会在全部的php-fpm进程中共享。在比较大的应用中,这能够很是有效地节约内存,提升应用的性能。
  9. 这个选项的值是以兆字节(megabytes)做为单位,若是把它设置为16,则表示16MB,默认是4MB,这是一个比较低的值。
  10. opcache.max_accelerated_files (default "2000")
  11. ;这个选项用于控制内存中最多能够缓存多少个PHP文件。这个选项必须得设置得足够大,大于你的项目中的全部PHP文件的总和。
  12. 设置值取值范围最小值是 200,最大值在 PHP 5.5.6 以前是 100000PHP 5.5.6 及以后是 1000000。也就是说在2001000000之间。
  13. 你能够运行“find . -type f -print | grep php | wc -l”这个命令来快速计算你的代码库中的PHP文件数。
  14. opcache.max_wasted_percentage (default "5")
  15. ;计划从新启动以前,“浪费”内存的最大百分比。
  16. opcache.use_cwd (default "1")
  17. ;若是启用,OPcache将在哈希表的脚本键以后附加改脚本的工做目录, 以免同名脚本冲突的问题。禁用此选项能够提升性能,可是可能会致使应用崩溃
  18. opcache.validate_timestamps (default "1")
  19. ;若是启用(设置为1),OPcache会在opcache.revalidate_freq设置的秒数去检测文件的时间戳(timestamp)检查脚本是否更新。
  20. 若是这个选项被禁用(设置为0),opcache.revalidate_freq会被忽略,PHP文件永远不会被检查。这意味着若是你修改了你的代码,而后你把它更新到服务器上,再在浏览器上请求更新的代码对应的功能,你会看不到更新的效果,你必须使用 `opcache_reset()` 或者 `opcache_invalidate()` 函数来手动重置 OPcache。或者重重你的web服务器或者php-fpm 来使文件系统更改生效。
  21. 我强烈建议你在生产环境中设置为0why?由于当你在更新服务器代码的时候,若是代码较多,更新操做是有些延迟的,在这个延迟的过程当中必然出现老代码和新代码混合的状况,这个时候对用户请求的处理必然存在不肯定性。最后,等全部的代码更新完毕后,再平滑重启PHPweb服务器。
  22. opcache.revalidate_freq (default "2")
  23. ;这个选项用于设置缓存的过时时间(单位是秒),当这个时间达到后,opcache会检查你的代码是否改变,若是改变了PHP会从新编译它,生成新的opcode,而且更新缓存。值为“0”表示每次请求都会检查你的PHP代码是否更新(这意味着会增长不少次stat系统调用,译注:stat系统调用是读取文件的状态,这里主要是获取最近修改时间,这个系统调用会发生磁盘I/O,因此必然会消耗一些CPU时间,固然系统调用自己也会消耗一些CPU时间)。能够在开发环境中把它设置为0,生产环境下不用管。
  24. 若是 `opcache.validate_timestamps` 配置指令设置为禁用(设置为0),那么此设置项将会被忽略。
  25. opcache.revalidate_path (default "0")
  26. ;在include_path优化中启用或禁用文件搜索
  27. 若是被禁用,而且找到了使用的缓存文件相同的include_path,该文件不被再次搜索。所以,若是一个文件与include_path中的其余地方相同的名称出现将不会被发现。若是此优化对此有效,请启用此指令你的应用程序,这个指令的默认值是禁用的,这意味着该优化是活跃的。
  28. opcache.fast_shutdown(默认“0”)
  29. ;若是启用,则会使用快速中止续发事件。 所谓快速中止续发事件是指依赖 Zend 引擎的内存管理模块 一次释放所有请求变量的内存,而不是依次释放每个已分配的内存块。
  30. 该指令已在PHP 7.2.0中被删除。快速关机序列的一个变种已经被集成到PHP中,而且若是可能的话将被自动使用。

验证opcache是否生效

当咱们开启Opcache后,而后也配置好了相关的配置,那么如何验证是否已经成功了呢?

写了简单的小例子,先把检查时间设置为10秒,也就是说10秒内,不会去检查文件是否有更新,直接用缓存中的opcode:

  1. zend_extension=opcache.so
  2. [opcache]
  3. opcache.enable=1
  4. opcache.memory_consumption=128
  5. opcache.interned_strings_buffer=8
  6. opcache.max_accelerated_files=4000
  7. opcache.revalidate_freq=10
  8. opcache.fast_shutdown=1
  9. opcache.enable_cli=1

而后一个简单的例子:

  1. //php71.php
  2. <?php
  3. $a = '12';
  4. echo $a;

启动一个php自带的web服务:

  1. php -S 127.0.0.1:8088

而后再浏览器里打开:

  1. http://127.0.0.1:8088/php71.php

结果是:12

而后,手动改下:

  1. //php71.php
  2. <?php
  3. $a = '34';
  4. echo $a;

若是你手速快,迅速的去刷新浏览器,10次内,你会发现,结果仍是12。不是 34。

说明,Opcache 已经生效了。

再来改一下,把opcache.validate_timestamps=0设置为0,则表示,永远不去检查文件是否更新。

而后,你刷新页面,数字永远是12。除非你ctrl+c 关闭web服务,再启动web服务,才会生效变成 34。

因此,在通常的公司代码上线发布后,都会平滑重启php或者web服务器

opcache相关的几个函数

虽然opcahce是php内置的行为,只要你开启了,就会生效,不须要像传统的redis或者memcache须要手动写代码才能使用。可是php也提供了若干个opcache相关的函数。

  • opcache_compile_file — 无需运行,便可编译并缓存 PHP 脚本
  • opcache_get_configuration — 获取php.ini中的配置信息
  • opcache_get_status — 获取缓存的状态信息
  • opcache_invalidate — 废除脚本缓存
  • opcache_is_script_cached — 一个php文件是否被缓存
  • opcache_reset — 重置状况全部的缓存内容

咱们来一一看下。

opcache_compile_file

使用此函数,能够无需运行php脚本,便可编译并缓存 PHP 脚本。该函数可用于在 Web 服务器重启以后初始化缓存,俗称缓存预热。

注意:文件必须填写完整全路径

咱们仍是举例子说明:

php71.php

  1. $a = '5678';
  2. echo $a;
  3. //是否被缓存
  4. var_dump(opcache_invalidate('/Users/tencent/php/php71.php'));
  5. //查看缓存状态
  6. var_dump(opcache_get_status());

每次重启web服务器,第一次刷新浏览器这个页面,查看打印:

  1. 5678
  2. bool(false)
  3. .....
  4. ["hits"]=> int(0)
  5. .....

能够,看出,第一次进来,是没有被缓存的,第二次刷新,就被缓存住了。

  1. 5678
  2. bool(true)
  3. .....
  4. ["hits"]=> int(1)
  5. .....

opcache_get_configuration

查看php.ini中的配置项,和php.ini里的设置同样,并列出全部的配置,以数组array的形式呈现,用 json_encode 打印出来:

  1. {
  2. "directives": {
  3. "opcache.enable": true,
  4. "opcache.enable_cli": true,
  5. "opcache.use_cwd": true,
  6. "opcache.validate_timestamps": true,
  7. "opcache.validate_permission": false,
  8. "opcache.validate_root": false,
  9. "opcache.inherited_hack": true,
  10. "opcache.dups_fix": false,
  11. "opcache.revalidate_path": false,
  12. "opcache.log_verbosity_level": 1,
  13. "opcache.memory_consumption": 134217728,
  14. "opcache.interned_strings_buffer": 8,
  15. "opcache.max_accelerated_files": 4000,
  16. "opcache.max_wasted_percentage": 0.05,
  17. "opcache.consistency_checks": 0,
  18. "opcache.force_restart_timeout": 180,
  19. "opcache.revalidate_freq": 10,
  20. "opcache.preferred_memory_model": "",
  21. "opcache.blacklist_filename": "",
  22. "opcache.max_file_size": 0,
  23. "opcache.error_log": "",
  24. "opcache.protect_memory": false,
  25. "opcache.save_comments": true,
  26. "opcache.enable_file_override": false,
  27. "opcache.optimization_level": 2147467263,
  28. "opcache.lockfile_path": "/tmp",
  29. "opcache.file_cache": "",
  30. "opcache.file_cache_only": false,
  31. "opcache.file_cache_consistency_checks": true
  32. },
  33. "version": {
  34. "version": "7.2.0",
  35. "opcache_product_name": "Zend OPcache"
  36. },
  37. "blacklist": []
  38. }

opcache_get_status

获取opcache的缓存状态以及缓存了哪些文件等信息,能够说是用的作多的一个脚本了。

打印出来:

  1. {
  2. "opcache_enabled": true,
  3. "cache_full": false,
  4. "restart_pending": false,
  5. "restart_in_progress": false,
  6. "memory_usage": {
  7. "used_memory": 18278720,
  8. "free_memory": 115919680,
  9. "wasted_memory": 19328,
  10. "current_wasted_percentage": 0.014400482177734375
  11. },
  12. "interned_strings_usage": {
  13. "buffer_size": 8388608,
  14. "used_memory": 428056,
  15. "free_memory": 7960552,
  16. "number_of_strings": 9963
  17. },
  18. "opcache_statistics": {
  19. "num_cached_scripts": 1,
  20. "num_cached_keys": 1,
  21. "max_cached_keys": 7963,
  22. "hits": 2,
  23. "start_time": 1516850948,
  24. "last_restart_time": 0,
  25. "oom_restarts": 0,
  26. "hash_restarts": 0,
  27. "manual_restarts": 0,
  28. "misses": 4,
  29. "blacklist_misses": 0,
  30. "blacklist_miss_ratio": 0,
  31. "opcache_hit_rate": 33.33333333333333
  32. },
  33. "scripts": {
  34. "/Users/tencent/php/php71.php": {
  35. "full_path": "/Users/tencent/php/php71.php",
  36. "hits": 0,
  37. "memory_consumption": 6432,
  38. "last_used": "Thu Jan 25 11:32:03 2018",
  39. "last_used_timestamp": 1516851123,
  40. "timestamp": 1516851119
  41. }
  42. }
  43. }

opcache_invalidate

废除(删除)一个文件的缓存。能够针对一个文件的清楚缓存。注意:文件必须填写完整全路径

  1. //清楚 php71.php缓存
  2. var_dump(opcache_invalidate('/Users/tencent/php/php71.php')); // bool(true)

opcache_is_script_cached

查看一个文件是否被缓存。注意:文件必须填写完整全路径

  1. var_dump(opcache_is_script_cached('/Users/tencent/ams-swoole-framework/php71.php'));
  2. //bool(true)
  3. var_dump(opcache_is_script_cached('/Users/tencent/ams-swoole-framework/php73.php'));
  4. // bool(false)

opcache_reset

重置全部的opcache缓存。注意:这个函数很危险,他会清空当前项目的全部opcache缓存:

  1. var_dump(opcache_reset()); //bool(true)

opcache图形化管理工具

上面的函数命令用起来可能没那么方便,基于上面的这些函数,有2个GUI的图形化管理工具,还不错。

1. 拥有漂亮的图形化界面的项目

https://github.com/PeeHaa/OpCacheGUI

下载后,将config.sample.php 复制一份成为:config.php。并修改帐户密码和时区:

  1. return [
  2. 'username' => 'root',
  3. 'password' => '$2y$10$XIlZ702pFKgRozYUuvaI4uZcumv19bysFo6PnviZIKlN8IvEeXVXu', //root
  4. 'whitelist' => [
  5. 'localhost',
  6. '127.0.0.1',
  7. ],
  8. 'language' => 'en',
  9. 'timezone' => 'Asia/Shanghai',
  10. 'error_reporting' => E_ALL,
  11. 'display_errors' => 'Off',
  12. 'log_errors' => 'On',
  13. 'uri_scheme' => Router::URL_REWRITE
  14. ];

而后在浏览器访问,输入帐户密码:root root:

http://127.0.0.1:8089/index.php

2. 单个PHP文件, 方便部署的项目

https://github.com/rlerdorf/opcache-status

下载后,而后在浏览器访问:

http://127.0.0.1:8089/opcache.php

opcache性能测试

那么,开启opcache性能是否有很大的性能提高呢?

相关文章
相关标签/搜索