使用 Zend Opcache 加速 PHP

Optimizer+ 是 Zend 开发的闭源但可以免费使用的 PHP 优化加速组件,是第一个也是最快的 opcode 缓存工具。现在,Zend 科技公司将 Optimizer+ 在 PHP License 下开源成为 Zend Opcache。现在,Opcache 已经是 PHP 7 的一部分了。

Zend OPcache 通过 opcode 缓存和优化提供更快的 PHP 执行过程。它将预编译的脚本文件存储在共享内存中供以后使用,从而避免了从磁盘读取代码并进行编译的时间消耗。同时,它还应用了一些代码优化模式,使得代码执行更快。

1. 什么是 opcode 缓存?

当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。Opcode cache 的目地是避免重复编译,减少 CPU 和内存开销。如果动态内容的性能瓶颈不在于 CPU 和内存,而在于 I/O 操作,比如数据库查询带来的磁盘 I/O 开销,那么 opcode cache 的性能提升是非常有限的。但是既然 opcode cache 能带来 CPU 和内存开销的降低,这总归是好事 —— 本着环保的态度,也应该尽量减少消耗不是? :D

现代操作码缓存器(Optimizer+,APC2.0+,其他)使用共享内存进行存储,并且可以直接从中执行文件,而不用在执行前“反序列化”代码。这将带来显着的性能加速,通常降低了整体服务器的内存消耗,而且很少有缺点。

2. Optimizer+ 与 APC 的优缺点对比

Optimizer+ 于 2013年3月中旬改名为 Opcache。

根据 PHP wiki 上的讨论,Zend Opcache 即将整合到 php 5.5 中。作为 APC 的竞争对手,新生的 Zend Opcache 很有可能取代 APC 的位置,虽然 OptimizerPlus 没有象 APC 那样的 user cache 功能。

Optimizer+ 相对 APC 的优点

  1. 性能。根据测试,Zend Optimizer+ 始终优于 APC。随代码差异,每秒钟处理的请求数高 5~20%。Google doc 上记录的测试结果中,WordPress 2.1.1(不知道为什么不用个新版本的 WP 来测试),性能提高约 8%。理论上来说,对于 WP 3.5.1,性能应该也能得到大约 5~10% 的提升吧。对于运行 WordPress 的服务器而言,使用 Optimizer+ 可以显著降低 CPU 使用率和提高页面加载速度(graphics here)。
  2. 支持新的 PHP 版本。Zend 和 PHP 社区都会帮助 Optimizer+ 能够支持最新版本的 PHP。
  3. 可靠性。Optimizer+ 拥有可选的损坏检测能力,可以防止因数据损坏而导致的服务器崩溃。
  4. 更好的兼容性。PHP 社区打算让 Optimizer+ 与社区支持的所有 PHP 版本相兼容。

APC 相对 Optimizer+ 的优势

  1. APC 有数据缓存 API,而 Optimizer+ 没有。
  2. APC 能够回收旧的无效的脚本占用的内存。APC 有内存管理器,可以将那些不再使用的脚本关联的内存进行回收。而 Optimizer+ 不同,它将这样的内存标记为“脏的”,但并不会回收它们。一旦“脏的”内存占用配置阈值的百分比达到一定值,Optimizer+ 就将自己重新启动。这种行为在稳定性上既有优势也有劣势。

3. 使用 Zend Opcode

现在已经可以使用 Zend Opcache 替代 APC 作为 PHP 优化加速工具了。目前的 Zend Opcode 兼容 PHP 5.2.*、5.3.*、5.4.* 和 PHP-5.5 开发版。不过,将来会取消对 PHP 5.2 的支持。而在 PHP 7 中,Opcache 已经是 PHP 的一部分了。

注意:Zend Opcache 与 eaccelerator 相冲突。要安装 Zend Opcache,可能需要先卸载 eaccelerator —— 如果你用了这个加速模块的话。

从源码安装并配置

Zend Opcache 的源代码托管在 github 上,目前还是叫做 ZendOptimizerPlus。在 PHP 7 中,直接从官方源安装 php-opcache 软件包就可以了。

安装步骤详见其 README 文件。

注意:

  1. 最好在本地虚拟机里测试之后再部署到自己的服务器上;
  2. 安装前最好先删除 eacceleratro、xcache 或 apc 等组件。

顺便说一句,从源码编译安装时需要用到 php-devel。README 中快速安装一节的开头就用到,

$PHP_DIR/bin/phpize

如果不清楚 phpize 的路径,可以,

whereis phpize

README 文件中也有相应的推荐优化设置。

在 openSUSE Linux 中安装

前面提到了,从 PHP7 开始,opcache 已经包含在 PHP 的正式发行中了。所以安装 PHP7 的时候可以直接安装 php7-opcache 而不需要额外的安装源。比如在 openSUSE Leap 15.1 中,直接安装,

zypper install php7-opcache

默认的配置文件在 /etc/php7/conf.d/opcache.ini,几乎是空的。

从 EPEL 源安装

我不喜欢从源码编译安装程序,一个是水平有限,一个就是怕麻烦。下面介绍从 EPEL 安装源安装 Zend Opcache,以 CentOS 上的操作为例,基于我的 VPS 的配置。而在 PHP 7 中,直接从 Linux 发行版的官方源安装 php-opcache 软件包就可以了。

yum install php-opcache

当然,对于 PHP 7 之前的版本,还是使用 EPEL 社区提供的 Zend Opcache 的安装包,可以直接 yum 安装。当然,前提是已经配置使用了 EPEL 的安装源。如果没有,可以参考这里

提醒一下,REMI 安装源上的 PHP 已经是 5.4 版本了。鉴于有人测试说 WordPress 在 PHP 5.4 上的性能要优于在 PHP 5.3 上的性能(10% faster and lower ram consuming),顺便升级一下 PHP 也不是什么坏事。

操作步骤:

  1. 配置使用 epel 安装源。已有则跳过。
  2. 删除 eaccelerator、xcache、apc:
    yum remove php-eaccelerator php-xcache php-apcu

    没有使用则跳过。

  3. 对系统执行升级:
    yum update

    目的是根据 remi 安装源的状态升级当前的 php 等软件到 remi 支持的最新版本。此时,可以看到系统有类似下面的输出:

    Updating   : php-common-5.4.14-1.el6.remi.i686                                                         1/26
    
    WARNING : These php-* RPM are not official Fedora / Red Hat build and
    overrides the official ones. Don't file bugs on Fedora Project nor Red Hat.
    
    Use dedicated forums http://forums.famillecollet.com/
    
    warning: /etc/php.ini created as /etc/php.ini.rpmnew
      Updating   : mysql-libs-5.5.31-1.el6.remi.i686                                                         2/26
    
    WARNING : This MySQL RPM is not an official Fedora / Red Hat build and it
    overrides the official one. Don't file bugs on Fedora Project nor Red Hat.
    Use dedicated forums http://forums.famillecollet.com/
    
    warning: /etc/my.cnf created as /etc/my.cnf.rpmnew

    表示我们现在要从 Fedora / Red Hat 的版本迁移到 Remi 版本了,所以不要去 Fedora / Red Hat 寻求帮助了。呵呵,貌似出问题都是在网上找,还真是很少到官方论坛里提问。像我这样的入门级用户,也不会遇到那么深度的问题。

  4. 安装 Zend Opcache(pecl 版本):
    yum install php-pecl-zendopcache

    安装时产生的 opcache 的配置文件位于 CentOS 中默认的 /etc/php.d 目录中:

    opcache-default.blacklist
    opcache.ini

    这个配置文件采用的基本就是 README 中的推荐设置,只有几个地方需要修改。PHP 7 中的配置文件为 `/etc/php.d/10-opcache.ini`。

    vi /etc/php.d/opcache.ini

    对照如下推荐配置修改并保存即可(可参考完整的 Zend Opcache 配置信息):

    opcache.memory_consumption=128
    opcache.interned_strings_buffer=8
    opcache.max_accelerated_files=4000
    opcache.revalidate_freq=60
    opcache.fast_shutdown=1
    opcache.enable_cli=1
  5. 不需要修改 php.ini 配置,重起 Apache 服务使之生效:
    service httpd restart

查询一下看看是否正确启动了:

php -v

输出结果类似于:

PHP 5.4.14 (cli) (built: Apr 11 2013 11:04:35)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
    with Zend OPcache v7.0.1, Copyright (c) 1999-2013, by Zend Technologies

设置例外

也许服务器上某些内容,比如正在进行调试的网站等,我们不希望对其进行 OPcache。那就可以通过黑名单来将需要例外的文件排除掉。

在 OPcache 的配置文件中有一行配置,如下,

opcache.blacklist_filename=/etc/php.d/opcache*.blacklist

该配置指定用于存储文件名黑名单的那个文件。很显然这里使用通配符 * 来指定了一系列文件而不仅仅是特定某个文件。可以一直启用这一行。等到需要排除某些文件的时候,就编辑对应的黑名单文件。例如,针对 /srv/www/sites/devSite 文件夹下的所有文件,编辑(或者新建)文件,

vim /etc/php.d/opcache-devSite.blacklist

内容为,

/srv/www/sites/devSite/*

嗯,只有这么一行内容。通配符 * 表示所有 devSite 文件夹下的文件。

完了之后重新启动 php-fpm 服务就可以了。

systemctl restart php-fpm

4. 体会

PHP 上有不少 opcode cache 组件,如 APC、eAccelerator、XCache 等。(参见 Wikipedia 上的 PHP accelerators 列表。)看 PHP wiki 上的意思,这个新引入的 Zend Opcache 的性能应该是最好的。不管用哪个组件,总归是用一个才好。

对于小型的服务器,似乎这几个组件的性能差异并不太明显。我的想法是,既然用了,那就用个最好的吧。但是如果你正在使用别的 opcode cache,比如上面提到的这几个中的一个,从性能提升上讲,倒是没必要立刻就换。

对这个站,首页生成时间:仅使用 PHP 的时候,大约 0.9s;使用 eAccelerator 大约 0.63s;使用 Zend Opcache 后大约 0.55s。测试得非常简陋,多打开几次看看 WP Super Cache 提供的页面生成时间,估计一个平均数。

登录到系统里看了看 Apache 进程的内存占用。之前一个进程不多大一会儿就能占用 40MB 以上的内存,现在基本上没有高于 40MB 的了。只是不知道是 php 5.4 的功劳呢,还是 Zend Opcache 的功劳。

不知道您觉得这个 Zend Opcache 的效果如何?如果您有兴趣,不妨留言写下您的测试结果。

更新

2019.03.16 补充更新 PHP 7 中 Opcache 的情况说明。©

本文发表于水景一页。永久链接:<https://cnzhx.net/blog/zendopcache-accelerate-php/>。转载请保留此信息及相应链接。

37 条关于 “使用 Zend Opcache 加速 PHP” 的评论

  1. 我也装了个,但不知道怎么看运行状态,apc人家包里面还有个php文件,xcache也有php文件可以看命中率之类的东西。
    这玩意啥都看不到,知道在运行,但不知道运行的怎么样。

  2. FreeBSD下PHP5.5.x正常,Win8下PHP5.5.x超出最大请求后报The CGI/FastCGI stopped working,Google许久无解,看来得去细读OPcache源码了。

  3. 引用通告: 如何在AWS EC2上面安裝Zend OPcache加速PHP | 阿維雜記本 (Wei's Blog)

  4. 引用通告: 新一代 PHP加速插件 Zend Opcache | 农夫庄园

  5. 引用通告: linux下安装opcache扩展(原创) | 学习笔记

  6. 博主您好,我有个问题想咨询一下。
    普通的PHP加速(apc/EA/xcache)应该是php文件编译源代码成为opcode树的缓存。每次执行PHP即使有加速也应该也会从硬盘加载PHP文件。只是减少了PHP文件的编译过程从而提高PHP的执行速度。
    如您的博客Zend OPcache 通过 opcode 缓存和优化提供更快的 PHP 执行过程。它将预编译的脚本文件存储在共享内存中供以后使用,从而避免了从磁盘读取代码并进行编译的时间消耗。
    zend opcache是不是不再加载PHP文件,直接从编译源代码的opcode执行了?谢谢先

    • 差不多是你说的这个意思吧。时间长了,我又看了看,过程是:
      如果网站访问用到某个php,则将其编译并缓存在内存,同时存一份到硬盘中;下次再使用该php的时候,就不需要读php源文件,而是直接用这个缓存的编译过的结果来执行运算。
      但是,如果某个php很长时间不用,其编译结果可能会被从内存中挤出去,但是还在硬盘上,下次使用的时候直接读硬盘上的那份结果,不过也是编译过的,不需要重新编译。
      另外,如果该php经过了修改,则需要将它当成一个新的php文件来处理。

  7. 还是用apc 更多一些,我对这apc eacc wincache 也做个一些测试,wincache 的表现也相当不错,当然只在windows平台上,eacc 我不知道是不是设定的有问题 或者编译的有问题,在网站上跑一段时间会崩溃 而且性能好的时候,能超过其他的,性能不好的时候基本上没有加速,近一年一直是有apc 稳定也差不多,现在opcache也来试试

    • 我记得 eacc 本身就有崩溃的毛病,应该在文中指出来了。
      反正,到 PHP 5.5 的话官方就切换到 opcache 了,所以我这基本属于随大流 :D

  8. 引用通告: PHP5.4 + Zend Opcache 加速 wordpress 小结 - 乱七八糟 - 裁纸刀下

  9. 引用通告: Linode VPS 上 CentOS 6 安装 LAMP + phpMyAdmin 记录 | 水景一页

  10. 才安装Zend Opcache,cpu占用减少了很多,运行时间下降了很多,感觉很不错。

    • 时间久了,我也不太记得。它们两个完成的主要任务是一样的,为什么要同时启用呢?
      不过你可以试试看。试过了记得回复说一声结果啊,谢谢了 :D

  11. 引用通告: 我的 VPS 学习之路 | 水景一页

  12. 引用通告: WordPress + Memcached 部署以及一些关于缓存的看法 | 水景一页

  13. 引用通告: PHP5 OPcache |

  14. 你好,我在云服务器上,装了 军哥的LNMP1.2 + Zend Opcache + phpmyadmin, 碰到了 后2者不能共存,要是 允许 Zend Opcache了,phpmyadmin就打不开了,只好禁止 Zend Opcache,请问这是什么原因? 谢谢。

    • 按我的理解,Opcache 跟 phpMyAdmin 不是一个层面的东西,实在不理解它们怎么会有冲突。对不起,这个问题我恐怕帮不上你什么忙。而且我对 Nginx 没有任何经验。
      不知道你有没有对比检查系统错误记录和服务器错误记录,有什么特别的提示吗?

      • WordPress Version 4.3.2 + Centos6.4 + LNMP1.2 + PHP 5.4.41 + mysql 5.5.42 + Zend Opcache v7.0.2 + phpmyadmin-3.3.5.1 + webbench-1.5
        目前phpmyadmin这个版本所有的都可以正常操作,唯独不能 点【导出】那里, 当把opcache禁止了,就可以【导出】了。

        • 就像我前面解释的,对你这个问题我也没什么思路。建议你去 LNMP 的论坛问问。

      • slow.log提示

        因为没有与 phpMyAdmin相关的内容,故全部清除。cnzhx 编辑于 2016.01.19。

        php-fpm.log提示

        [17-Jan-2016 19:53:28] WARNING: [pool www] child 25466, script '/home/wwwroot/www.feicuizaixian.com/xmlrpc.php' (request: "POST /xmlrpc.php") execution timed out (10.291706 sec), terminating
        因为没有与 phpMyAdmin相关的内容,故全部清除,只留个例子。cnzhx 编辑于 2016.01.19。
        

        那里错了,
        谢谢

        • 最新的提示,
          php-fpm.log

          因为没有与 phpMyAdmin相关的内容,故全部清除。cnzhx 编辑于 2016.01.19。

          谢谢

          • 因为你提供的日志里面没有与 phpMyAdmin 相关的内容,我自作主张给清除了代码,还请见谅。
            系统里的日志生成是非常快也非常多的,很多内容对于解决问题并没有实质性帮助。如果你要看日志的话,最好适当隔离/清理一下环境,然后执行可以重现错误的操作,再提取日志内容。
            大致浏览一下日志内容,剔除一些明显与所要解决的问题无关的内容。比如你提供的日志里面 {wordpress}/xmlrpc.php 是 WP 的 API,与 phpMyAdmin 应该没有关系。
            很抱歉这个问题我帮不了你。

            • 你好

              查了,php.ini,

              [Zend ZendGuard Loader]
              ;zend_extension=/usr/local/zend/ZendGuardLoader.so
              zend_loader.enable=1
              zend_loader.disable_licensing=0
              zend_loader.obfuscation_level_support=3
              zend_loader.license_path=
              [opcache]
              zend_extension=/usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/opcache.so
              ;上面zend_extension路径为opcache.so的路径
              opcache.force_restart_timeout=3600
              opcache.memory_consumption=128
              opcache.interned_strings_buffer=8
              opcache.max_accelerated_files=4096
              opcache.revalidate_freq=60
              opcache.fast_shutdown=1
              opcache.enable_cli=1
              opcache.enable=1
              ;opcache.blacklist_filename=/home/wwwroot/www.zaixianfeicui.com/blacklist

              定义了2次 zend_extension
              注释了

              ;zend_extension=/usr/local/zend/ZendGuardLoader.so

              即可了,
              谢谢。

时间过去太久,评论已关闭。
如果您有话要说,请到讨论区留言并给出此文章链接。
谢谢您的理解 :-)