PHP 整体结构解析和Opcache优化案例
大约 5 分钟
PHP 整体结构解析和Opcache优化案例
PHP由以下部分组成:
- Zend Zend 引擎整体用C语言实现,是 PHP 的内核部分,它负责将 PHP 代码翻译(词法、语法解析等一系列编译过程)为可执行的 opcode 操作码,并实现相应的处理方法、基本的数据结构(如 hashtable、oo)、内存分配及管理、提供相应的 API 方法供外部调用。Zend 是一切的核心,所有的外围功能均围绕 Zend 实现。
- Extension 围绕着 Zend 引擎,Extensions 通过组件化的方式提供各种基础服务,我们常见的各种内置函数(例如变量操作函数、字符串操作函数等)以及标准库等都是通过 Extensions 来实现。用户也可以根据需要实现自己的 Extension 组件以达到功能扩展、性能优化等目的。
- SAPI SAPI 全称是 Server Application Programming Interface,译为“服务器应用程序编程接口”。SAPI 通过一系列钩子函数,使得 PHP 可以和外围交互数据,这是 PHP 非常优雅和成功的一个设计,通过 SAPI 成功的将 PHP 本身和上层应用解耦隔离,PHP 可以不再考虑如何针对不同应用进行兼容,而应用本身也可以针对自己的特点实现不同的处理方式。SAPI 提供了一个和外部通信的接口,常见的 SAPI 有:cgi、fast-cgi、cli、apache 模块的 DLL、isapi 等。
在这里对CGI和FAST-CGI展开说:
CGI
CGI 即通用网关接口(Common Gateway Interface),它是一段程序,通俗的讲 CGI 就象是一座桥,把网页和 WEB 服务器中的执行程序连接起来,它把 HTML 接收的指令传递给服务器的执行程序,再把服务器执行程序的结果返还给 HTML。
CGI 的跨平台性能极佳,几乎可以在任何操作系统上实现。
CGI 在遇到连接请求后,会先要创建 CGI 的子进程,激活一个 CGI 进程,然后处理请求,处理完后结束这个子进程,这就是 fork-and-execute 模式。
综上所述,使用 CGI 方式的服务器有多少连接请求就会有多少 CGI 子进程,子进程反复加载 会导致 CGI 性能低下。当用户请求数量非常多时,会大量挤占系统的资源,如内存、CPU 时间等,造成性能低下。
FastCGI
fast-cgi 是 CGI 的升级版本,FastCGI 像是一个常驻(long-live)型的 CGI,它激活后可以一直执行着。
FastCGI 的工作原理:
- Web Server 启动时载入 FastCGI 进程管理器(IIS ISAPI 或 Apache Module);
- FastCGI 进程管理器自身初始化,启动多个 CGI 解释器进程(可见多个 php-cgi)并等待来自 Web Server 的连接;
- 当客户端请求到达 Web Server 时,FastCGI 进程管理器选择并连接到一个 CGI 解释器。Web server 将 CGI 环境变量和标准输入发送到 FastCGI子进程 php-cgi;
- FastCGI 子进程完成处理后将标准输出和错误信息从同一连接返回 Web Server。当 FastCGI 子进程关闭连接时,请求便处理完成了。FastCGI 子进程接着等待并处理来自 FastCGI 进程管理器(运行在 Web Server 中)的下一个连接。 在 CGI 模式中,php-cgi 在此便退出了。
PHP代码整体的执行流程
- 将PHP代码转换为Tokens(语言片段)
- 将Tokens转换为简单而有意义的表达式
- 将表达式编译成Opcode
- 依次执行Opcode 那么在这里得出来所有的PHP代码都是要编译成opcode进行运行的,那么如果php文件本身没有被修改过,那么文件就会被重复编译,从而浪费cpu性能,所以opcache本身就是为了解决这个问题而存在的。在开启了opcache之后,整体流程则变成以下情况:
- 判断是否是已编译过的php文件
- 是,直接跳转到Process opcache阶段
- 否,将PHP代码转换为Tokens(语言片段)(Lexicon阶段)
- 将Tokens转换为简单而有意义的表达式(Parse阶段)
- 将表达式编译成Opcode,并添加opcache(create opcode阶段)
- 依次执行Opcode(Process opcache阶段)
Opcache
Opcache的作用
OPCache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销。主要是为了减少重复编译,从而减少CPU和内存的开销。
Opcache缓存的内容
- OPCode
- Interned String(可以理解为php请求生命周期中不需要释放的String,包括:变量名、类名、方法名、字符串、注释等)
Opcache的工作原理
Opcache工作原理其实是使用了共享内存机制,将需要缓存的内容放入到共享内存中,供其他进程使用。 因为Opcache在创建缓存的过程中不会阻止其他进程读取,所以在使用Opcache时要注意两点,不然会大量消耗资源:
- 不要给Opcache设置过期时间
- 不要在流量高峰期发布代码
Opcode配置案例:
vi /usr/local/webserver/php-8.2.12/etc/php.ini
查找[opcache],在[opcache]下面加上以下配置信息:
zend_extension="/usr/local/webserver/php-8.2.12/lib/php/extensions/no-debug-non-zts-20220829/opcache.so"
修改[opcache]已有的配置信息,需要修改的配置信息如下:
; Determines if Zend OPCache is enabled
opcache.enable=1
; Determines if Zend OPCache is enabled for the CLI version of PHP
opcache.enable_cli=1
; The OPcache shared memory storage size.
opcache.memory_consumption=128
; The maximum number of keys (scripts) in the OPcache hash table.
; Only numbers between 200 and 100000 are allowed.
opcache.max_accelerated_files=5000
; How often (in seconds) to check file timestamps for changes to the shared
; memory storage allocation. ("1" means validate once per second, but only
; once per request. "0" means always validate)
opcache.revalidate_freq=60
;jit配置
opcache.jit=1205
opcache.jit_buffer_size=64M
参考文献: