PHP7.4 Preload 特性了解与理解

PHP7.4 Preload 特性了解与理解

author: he xiaodong date: 2019-12-09

确保你的 php 是的 7.4 版本,preload 是 7.4 版本新特性

基础了解

  根据 rfc 描述,Preload 简明翻译是预加载,是基于 opcache 的一层升级,也是 opcache 的一部分。现有的 opcache 存储文件可以消除编译开销,但从缓存中获取文件并获取特定请求的上下文仍有相关成本。PHP 仍然需要检查源文件是否已被修改,将类和函数的某些部分从共享内存缓存复制到进程内存等。值得注意的是,由于每个 PHP 文件都完全独立于任何其他文件进行编译和缓存,因此在将文件存储在 opcode 缓存中时,我们无法解决存储在不同文件中的类之间的依赖关系,并且必须在每个请求的运行时重新链接类依赖项。

  Preload 的灵感来自为 Java HotSpot VM 设计的”类数据共享”技术。它旨在为用户提供以传统 PHP 模型提供的某些灵活性来换取性能的能力。在服务启动时(在运行任何应用程序代码之前),我们可能会将一组特定的 PHP 文件加载到内存中,并使其内容”永久可用”到该服务器将处理的所有后续请求。这些文件中定义的所有函数和类都可以对现成的请求使用,与内部实体(例如 strlen() 或异常)完全一样。通过这种方式,我们可以预加载整个或部分框架,甚至整个应用程序类库。它还将允许引入以 PHP 编写的”内置”函数(类似于 HHVM 的 sytemlib)。换算的灵活性包括服务器启动后无法更新这些文件(在文件系统上更新这些文件不会执行任何操作;需要重新启动 fpm 服务才能应用更改。此外,此方法与承载多个应用程序的服务器或多个版本的应用程序(对于具有相同名称的某些类具有不同的实现)不兼容,如果此类从一个应用的代码库预加载,则与从其他应用加载不同的类实现将发生冲突。

上手使用

整体就是开启,配置一下脚本文件,设置用户就行。首先需要修改配置文件 php.ini

[opcache]
zend_extension=opcache.so
opcache.enable=1             # 启用 opcache
opcache.enable_cli=1         # 仅针对 CLI 版本的 PHP 启用操作码缓存。通常被用来测试和调试。
opcache.preload=preload.php  # preload 脚本路径
opcache.preload_user=web     # preload 用户,安全考虑禁止 root 用户

对应 preload.php 文件,可以引入其他文件:

<?php

function xx()
{
    return 'hello preload!';
}

opcache_compile_file('other.php');

如果需要引入composer编译后的文件,可以这样:

<?php

$files = require __DIR__ . '/composer/autoload_classmap.php';

foreach (array_unique($files) as $file) {
    opcache_compile_file($file);
    // require_once($file);
}

一个要点是:如果你写了几个文件名称,而没有写他们的依赖文件,例如接口,trait 和父类,将会抛出警告,实际上没有预加载成功,将 opcache_compile_file 函数换成 require_once 函数就行,参见 opcache-compile-file 方法

还要一个第三方包协助生成 preload 脚本 – Composer-Preload,用法可以参考词包的 README。对于 composer 官方,issue 中有讨论,可能会在 2.0 里程碑版本推出这个特性。

局限性及注意点
  • 一个 php 只能有一个preload 配置选项,对于多项目的情况是局限性,类似共享虚拟云主机的情况无法解决。
  • 一台服务器的话,php-fpm 重启过程中会有少量时间消耗,这个时间会断开所有的链接,这个是需要评估的情况,可以考虑在深夜重启。多台主从服务器或者有高可用(HA)方案的时候,可以踢掉一台,重启一下 php-fpm 再加入就行,只是时间操作的成本,没有技术隐患。(涉及到另一个问题:php-fpm reload 的情况下,确定你的 worker 进行真正的全部 reload 了一下,有些情况下,有较长时间的定时任务在处理,必须等这个连接忙完才真正 reload,或者受 process_control_timeout 配置项影响,多久时间不完成就强制结束并重启,如果没有这个情况,php-fpm restart 最简单直接)。
  • 需要加载的文件不多的话,不能带来显著的提升,只有大的框架项目值得去预加载。需要评估是否加载 verdor 中全部的文件,文件越多需要的内存越大,只加载最关键的部分是最好的选择,较少的内存资源占用并带来性能提升。
  • 大框架多文件预加载情况下,遍历文件加入到 opcache 的预热过程需要消耗 CPU 资源,必要而短暂的耗时。

最大的隐患是技术人员在开发环境没有充分的场景测试一下,不愿意直接在生产环境启用

参考链接:

  1. github issue:An attempt to implemnt “preloading” ability. 主要看一下 Dmitry Stogov 大佬的解释。
  2. github issue:Preloading support
  3. RFC Preload
  4. Introduction to PHP 7.4 Preload
  5. Composer: How it should preload in PHP 7.4
  6. Opcache 配置选项手册
  7. Preloading in php7.4

© 原创文章,如有错误或指正 请联系 hexiaodong1992@outlook.com