PHP 8新特性之JIT对PHP应用性能的影响

前言

PHP 8 新特性

理解 PHP 8 的 JIT​zhuanlan.zhihu.com图标

即将发布的 PHP 8 最受大家关注的新特性就是引入了对 JIT 的支持,我已经简单介绍了 JIT 是什么以及与 Opcache 的区别,这里简单总结下:

  • JIT 是在 Opcache 优化的基础上结合 Runtime 信息将字节码编译为机器码缓存起来
  • 现有的 Opcache 优化不受任何影响,并且 PHP 的 JIT 是在 Opcache 中提供的
  • JIT 不是对 Opcache 替代,而是增强,在启用 JIT 的情况下,如果 Zend 底层发现特定字节码已经编译为机器码,则可以绕过 Zend VM 直接让 CPU 执行机器码,从而提高代码性能。

看起来很高大上,不过 JIT 主要针对 CPU 密集型操作优化效果明显,而目前主流的 PHP Web 应用都是 IO 密集型操作,那么 PHP 8 引入的 JIT 对这些 Web 应用的性能有没有提升呢?为此,特地编译安装了 PHP 8 Alpha 版本,并分别对命令行应用(CPU 密集型操作)和 Laravel 应用(IO 密集型操作)进行了简单的基准测试来探个究竟。

 

准备一个 Ubuntu 虚拟机

注:PHP 的 JIT 只能在 X86 架构下生效,所以使用 Intel CPU 的 PC、Mac、Linux 环境均可支持。

 

由于目前 PHP 8 还没有正式发布,只能下载源代码编译安装,所以需要准备一个 Linux 环境作为测试环境。不少同学跟我反映没怎么在 Windows 上演示过操作流程,所以今天我特地选择在 Windows 10 专业版中通过 WSL 来安装 Ubuntu 18.04 作为演示环境,这个比通过 Virtual Box 或者 VMWare 安装虚拟机简单多了,不得不说,从 Windows 10 开始,对开发者越来越友好了,虽然比起 Mac 还是有些距离,毕竟 Mac 是原生的类 Unix 系统。

 

言归正传,安装 WSL 版 Ubuntu 虚拟机 Windows 官方提供了相应的文档:Windows Subsystem for Linux Installation Guide for Windows 10 照着做就好了,非常简单,在 Windows 商店下载安装后,就可以点击启动按钮启动这个 Ubuntu 虚拟机了:

 

打开后的界面是这样的,看起来和一个终端窗口差不多:

这个虚拟机使用起来的体验比传统的虚拟机要简单一些,比如直接可以调用 Windows 宿主机的程序,比如 VS Code,在虚拟机中通过 Nginx 管理的 Web 应用也可以直接从 Windows 宿主机的浏览器访问,无需配置端口映射,所以用来作为本地 Linux 测试开发环境很方便。

当然,如果你不想尝鲜的话,使用传统的虚拟机或者原生的 Ubuntu 系统都可以。

演示项目初始化

接下来,我们需要通过上面打开的终端窗口在这个 Ubuntu 虚拟机中安装 Nginx,以及 PHP、Composer,通过以下几个命令就可以搞定了:

1
2
3
4
5
sudo apt install nginx
 
sudo apt install php php-zip php-mbstring
 
sudo apt install composer

  

然后通过 Composer 在 Nginx 默认 Web 根目录 /var/www 目录下安装用于演示的 Laravel Web 项目(下载速度慢可以配置 Composer 全局镜像):

1
sudo composer create-project --prefer-dist laravel/laravel blog 6.* -vvv

  

初始化完成后,可以通过 php artisan serve 测试下这个项目访问是否正常。这里就不演示了。

编译安装 PHP 8 测试版

完成上述准备工作后,就可以开始 PHP 8 测试版本的编译安装了,首先,我们从 Github 下载 PHP 8 测试版本源码(PHP 官网源码包下载太慢):

解压并进入源码根目录:

1
2
tar zxvf php-8.0.0alpha2.tar.gz
cd php-8.0.0alpha2

  

开始编译安装流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// 1、安装相关依赖库
 
sudo apt install -y pkg-config build-essential autoconf bison re2c libxml2-dev \
 
libsqlite3-dev libssl-dev libcurl4-openssl-dev libpng-dev libonig-dev libzip-dev
 
  
 
// 2、生成 configure 文件
 
./buildconf --force
 
  
 
// 3、配置构建流程
 
./configure --prefix=/usr/local/php8 \
 
--with-config-file-path=/usr/local/php8 \
 
--enable-mbstring  \
 
--enable-ftp  \
 
--enable-gd   \
 
--enable-mysqlnd \
 
--enable-pdo   \
 
--enable-sockets   \
 
--enable-fpm   \
 
--enable-xml  \
 
--enable-soap  \
 
--enable-pcntl   \
 
--enable-cli   \
 
--enable-json  \
 
--enable-tokenizer \
 
--enable-ctype \
 
--enable-bcmath  \
 
--with-openssl  \
 
--with-pear   \
 
--with-zlib  \
 
--with-iconv  \
 
--with-curl  \
 
--with-zip
 
  
 
// 4、构建
 
make
 
  
 
// 5、安装
 
sudo make install

  

最后一步执行成功后,会有 PHP 8 安装成功的提示文本,你也可以通过如下命令验证安装成功:

当前 PHP 8 被安装到了 /usr/local/php8 这个目录下。

初始化配置文件

编译安装的 PHP 8 需要自行拷贝和设置配置文件,我们首先将基础配置文件 php.ini 从源代码目录拷贝到 PHP 的安装目录:

1
sudo cp php.ini-production /usr/local/php8/php.ini

  

由于 JIT 是在 Opcache 扩展中提供的,所以需要先启动这个扩展,打开 /usr/local/php8/php.ini,取消对如下配置项的注释(删除前面的分号即可):

1
2
3
4
5
zend_extension=opcache.so
 
opcache.enable=1
 
opcache.enable_cli=1

  

然后来初始化 PHP-FPM 的配置文件。

先把 php8.0-fpm 二进制文件拷贝到 /etc/init.d 目录下(还是在 php-8.0.0alpha2 源码目录下操作):

1
2
3
sudo cp sapi/fpm/init.d.php-fpm /etc/init.d/php8.0-fpm
 
sudo chmod +x /etc/init.d/php8.0-fpm

  

进入 /usr/local/php8/etc 目录,初始化 PHP-FPM 配置文件:

1
2
3
cd /usr/local/php8/etc
 
sudo cp php-fpm.conf.default php-fpm.conf

  

通过 vim 编辑器打开 php-fpm.conf,修改如下配置项(同时取消前面的分号注释):

1
pid = /run/php/php8.0-fpm.pid

  

然后进入当前目录下的 php-fpm.d 子目录:

1
2
3
cd php-fpm.d
 
sudo cp www.conf.default www.conf

  

打开 www.conf,修改如下配置项(同时取消前面的分号注释):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
user = www-data
 
group = www-data
 
  
 
listen = /run/php/php8.0-fpm.sock
 
  
 
listen.owner = www-data
 
listen.group = www-data
 
listen.mode = 0660

  

命令行应用基准测试

完成上述准备工作后,就可以正式开始测试工作了。

首先,我们来测试命令行应用,PHP 官方在源码中提供了一个基准测试文件,我们进入源码所在目录 php-8.0.0alpha2,通过如下命令测试不启动 JIT 情况下代码运行情况:

/usr/local/php8/bin/php -d opcache.jit_buffer_size=0 Zend/bench.php

运行结果如下(运行时间,单位为 s):

然后,再通过下面这条命令测试启动 JIT 的情况下命令行代码的运行情况:

/usr/local/php8/bin/php -d opcache.jit_buffer_size=64M -d opcache.jit=1205 Zend/bench.php
注:关于 opcache.jit_buffer_size 配置项比较好理解,而 opcache.jit 配置项对应配置值的每个数字代表不同含义,具体可以参考鸟哥的这篇博客:PHP 8 新特性之 JIT 简介,里面讲得非常详细,一般对于命令行应用,将该配置值配置为 1205,对于 Web 应用,配置为 1235 或者 1255。

最终运行结果如下:

可以看到,在 CPU 密集型操作的命令行应用中,启用 JIT 与不启用相比,耗时降低了接近 60%,性能提升了 2 倍。

Web 应用基准测试

接下来,我们以 Laravel 演示项目为例,演示 PHP Web 应用中启用 JIT 与不启用性能有没有提升。

启动 PHP-FPM:

1
sudo /etc/init.d/php8.0-fpm start

  

在 Nginx 中配置一个新的虚拟主机(/etc/nginx/sites-available/blog):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
server {
 
    listen 80;
 
    server_name blog.test;
 
    root /var/www/blog/public;
 
  
 
    index index.html index.htm index.php;
 
  
 
    charset utf-8;
 
  
 
    location / {
 
        try_files $uri $uri/ /index.php?$query_string;
 
    }
 
  
 
    location = /favicon.ico { access_log off; log_not_found off; }
 
    location = /robots.txt  { access_log off; log_not_found off; }
 
  
 
    error_page 404 /index.php;
 
  
 
    location ~ \.php$ {
 
        fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
 
        fastcgi_index index.php;
 
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
 
        include fastcgi_params;
 
    }
 
  
 
    location ~ /\.(?!well-known).* {
 
        deny all;
 
    }
 
}

  

然后进入 /etc/nginx/sites-enable 目录,创建这个虚拟主机的软连接:

1
sudo ln -s /etc/nginx/sites-available/blog blog

  

启动 Nginx:

1
sudo service nginx start

  

在 Windows 系统的 C:\Windows\System32\drivers\etc\hosts 文件中添加虚拟域名与主机地址的映射:

1
127.0.0.1 blog.test

  

此时可以在 Windows 宿主机中通过浏览器访问对应的 Laravel 项目,表示部署成功:

然后,我们还是在 Windows 中,通过 ab 命令对 blog.test 首页进行压力测试(此时尚未启用 JIT):

1
ab -n 10 -c 10 http://blog.test/

  

注:-n 表示总请求数,-c 表示最大并发请求数。

测试结果如下,重点关注 RPS(每秒处理请求数):

最后,在 Ubuntu 虚拟机中,打开 PHP 8 的配置文件 /usr/local/php8/php.ini,在 Opcache 配置项下新增 JIT 配置:

opcache.jit=1235

opcache.jit_buffer_size=64M

 

配置完成后,重启 PHP-FPM 服务,再次回到 Windows 宿主机,通过 ab 命令对  页面进行压力测试:

ab -n 10 -c 10 -s 60 http://blog.test/
注:-s 表示超时时间。

运行结果如下:

可以看到在 IO 密集型操作的 Web 应用中,启用 JIT 与不启用相比,性能不但没有提升,反而有 10% 左右的损耗,至少在 Laravel 应用中是如此。

小结

当然,这里的测试仅限于的 Ubuntu 虚拟机环境(Windows WSL 版,配置是 8C8G),并且我也只是将 JIT 参数调整为官方建议的参数,没有做更多的对比测试,但是可以肯定的是 JIT 对 CPU 密集型操作优化效果很好,对 Web 应用性能是否有提升,取决于你的环境和配置的调优,因此 JIT 对 IO 密集型操作应用的性能优化效果有限,更适用于 CPU 密集型操作场景的性能优化,比如图像处理、机器学习等。

 

 

 

posted @   八重樱  阅读(2047)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示