跳至主要內容

PHP 整体结构解析和Opcache优化案例

Mr.Lexon大约 5 分钟environment

PHP 整体结构解析和Opcache优化案例

PHP由以下部分组成:

  1. Zend Zend 引擎整体用C语言实现,是 PHP 的内核部分,它负责将 PHP 代码翻译(词法、语法解析等一系列编译过程)为可执行的 opcode 操作码,并实现相应的处理方法、基本的数据结构open in new window(如 hashtable、oo)、内存分配及管理、提供相应的 API 方法供外部调用。Zend 是一切的核心,所有的外围功能均围绕 Zend 实现。
  2. Extension 围绕着 Zend 引擎,Extensions 通过组件化的方式提供各种基础服务,我们常见的各种内置函数(例如变量操作函数、字符串操作函数等)以及标准库等都是通过 Extensions 来实现。用户也可以根据需要实现自己的 Extension 组件以达到功能扩展、性能优化等目的。
  3. 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代码整体的执行流程

  1. 将PHP代码转换为Tokens(语言片段)
  2. 将Tokens转换为简单而有意义的表达式
  3. 将表达式编译成Opcode
  4. 依次执行Opcode 那么在这里得出来所有的PHP代码都是要编译成opcode进行运行的,那么如果php文件本身没有被修改过,那么文件就会被重复编译,从而浪费cpu性能,所以opcache本身就是为了解决这个问题而存在的。在开启了opcache之后,整体流程则变成以下情况:
  5. 判断是否是已编译过的php文件
  6. 是,直接跳转到Process opcache阶段
  7. 否,将PHP代码转换为Tokens(语言片段)(Lexicon阶段)
  8. 将Tokens转换为简单而有意义的表达式(Parse阶段)
  9. 将表达式编译成Opcode,并添加opcache(create opcode阶段)
  10. 依次执行Opcode(Process opcache阶段)

Opcache

Opcache的作用

OPCache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销。主要是为了减少重复编译,从而减少CPU和内存的开销。

Opcache缓存的内容

  1. OPCode
  2. Interned String(可以理解为php请求生命周期中不需要释放的String,包括:变量名、类名、方法名、字符串、注释等)

Opcache的工作原理

Opcache工作原理其实是使用了共享内存机制,将需要缓存的内容放入到共享内存中,供其他进程使用。 因为Opcache在创建缓存的过程中不会阻止其他进程读取,所以在使用Opcache时要注意两点,不然会大量消耗资源:

  1. 不要给Opcache设置过期时间
  2. 不要在流量高峰期发布代码

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

参考文献:

  1. PHP运行原理和机制open in new window
  2. PHP中的OPCode和OPCacheopen in new window
  3. PHP底层运行机制与原理open in new window
上次编辑于:
贡献者: lexon