搜索
首页后端开发php教程深入分析PHP Opcache工作原理

深入分析PHP Opcache工作原理

Jan 05, 2022 pm 02:01 PM
opcachephp

PHP项目中,尤其是在高并发大流量的场景中,如何提升PHP的响应时间,是一项十分重要的工作。

而Opcache又是优化PHP性能不可缺失的组件,尤其是应用了PHP框架的项目中,作用更是明显。

1. 概述

在理解 OPCache 功能之前,我们有必要先理解PHP-FPM + Nginx 的工作机制,以及PHP脚本解释执行的机制。

1.1 PHP-FPM + Nginx 的工作机制

请求从Web浏览器到Nginx,再到PHP处理完成,一共要经历如下五个步骤:

第一步:启动服务

  • 启动PHP-FPM。PHP-FPM 支持两种通信模式:TCP socket和Unix socket;
  • PHP-FPM 会启动两种类型的进程:Master 进程 和 Worker 进程,前者负责监控端口、分配任务、管理Worker进程;后者就是PHP的cgi程序,负责解释编译执行PHP脚本。
  • 启动Nginx。首先会载入 ngx_http_fastcgi_module 模块,初始化FastCGI执行环境,实现FastCGI协议请求代理
  • 这里要注意:fastcgi的worker进程(cgi进程),是由PHP-FPM来管理,不是Nginx。Nginx只是代理

第二步:Request => Nginx

  • Nginx 接收请求,并基于location配置,选择一个合适handler
  • 这里就是代理PHP的 handler

第三步:Nginx => PHP-FPM

  • Nginx 把请求翻译成fastcgi请求
  • 通过TCP socket/Unix Socket 发送给PHP-FPM 的master进程

第四步:PHP-FPM Master => Worker

  • PHP-FPM master 进程接收到请求
  • 分配Worker进程执行PHP脚本,如果没有空闲的Worker,返回502错误
  • Worker(php-cgi)进程执行PHP脚本,如果超时,返回504错误
  • 处理结束,返回结果

第五步:PHP-FPM Worker => Master => Nginx

  • PHP-FPM Worker 进程返回处理结果,并关闭连接,等待下一个请求
  • PHP-FPM Master 进程通过Socket 返回处理结果
  • Nginx Handler顺序将每一个响应buffer发送给第一个filter → 第二个 → 以此类推 → 最终响应发送给客户端

1.2 PHP脚本解释执行的机制

了解了PHP + Nginx 整体的处理流程后,我们接下来看一下PHP脚本具体执行流程,

首先我们看一个实例:

<?php
if (!empty($_POST)) {
    echo "Response Body POST: ", json_encode($_POST), "\n";
}

if (!empty($_GET)) {
    echo "Response Body GET: ", json_encode($_GET), "\n";
}

我们分析一下执行过程:

  • php初始化执行环节,启动Zend引擎,加载注册的扩展模块

  • 初始化后读取脚本文件,Zend引擎对脚本文件进行词法分析(lex),语法分析(bison),生成语法树

  • Zend 引擎编译语法树,生成opcode

  • Zend 引擎执行opcode,返回执行结果

在PHP cli模式下,每次执行PHP脚本,四个步骤都会依次执行一遍;

在PHP-FPM模式下,步骤1)在PHP-FPM启动时执行一次,后续的请求中不再执行;步骤2)~4)每个请求都要执行一遍

其实步骤2)、3)生成的语法树和opcode,同一个PHP脚本每次运行的结果都是一样的,

在PHP-FPM模式下,每次请求都要处理一遍,是对系统资源极大的浪费,那么有没有办法优化呢?

当然有,如:

  • OPCache:前身是Zend Optimizer+ ,是 Zend Server 的一个开源组件;官方出品,强力推荐
  • APC: Alternative PHP Cache 是一个开放自由的 PHP opcode 缓存组件,用于缓存、优化 PHP 中间代码;已经不更新了不推荐
  • APCu:是APC的一个分支,共享内存,缓存用户数据,不能缓存opcode,可以配合Opcache 使用
  • eAccelerate:同样是不更新了,不推荐
  • xCache:不再推荐使用了

2. OPCache 介绍

OPCache 是Zend官方出品的,开放自由的 opcode 缓存扩展,还具有代码优化功能,省去了每次加载和解析 PHP 脚本的开销。

PHP 5.5.0 及后续版本中已经绑定了 OPcache 扩展。

缓存两类内容:

  • OPCode
  • Interned String,如注释、变量名等

3. OPCache 原理

OPCache缓存的机制主要是:将编译好的操作码放入共享内存,提供给其他进程访问

这里就涉及到内存共享机制,另外所有内存资源操作都有锁的问题,我们一一解读。

3.1 共享内存

UNIX/Linux 系统提供很多种进程间内存共享的方式:

  • System-V shm API: System V共享内存,
    • sysv shm是持久化的,除非被一个进程明确的删除,否则它始终存在于内存里,直到系统关机;
  • mmap API:
    • mmap映射的内存在不是持久化的,如果进程关闭,映射随即失效,除非事先已经映射到了一个文件上
    • 内存映射机制mmap是POSIX标准的系统调用,有匿名映射和文件映射两种
    • mmap的一大优点是把文件映射到进程的地址空间
    • 避免了数据从用户缓冲区到内核page cache缓冲区的复制过程;
    • 当然还有一个优点就是不需要频繁的read/write系统调用
  • POSIX API: System V 的共享内存是过时的, POSIX共享内存提供了使用更简单、设计更合理的API.
  • Unix socket API

OPCache 使用了前三个共享内存机制,根据配置或者默认mmap 内存共享模式。

依据PHP字节码缓存的场景,OPCache的内存管理设计非常简单,快速读写,不释放内存,过期数据置为Wasted。

当Wasted内存大于设定值时,自动重启OPCache机制,清空并重新生成缓存。

3.2 互斥锁

任何内存资源的操作,都涉及到锁的机制。

共享内存:一个单位时间内,只允许一个进程执行写操作,允许多个进程执行读操作;

写操作同时,不阻止读操作,以至于很少有锁死的情况。

这就引发另外一个问题:新代码、大流量场景,进程排队执行缓存opcode操作;重复写入,导致资源浪费。

4. OPCache 缓存解读

OPCache 是官方的Opcode 缓存解决方案,在PHP5.5版本之后,已经打包到PHP源码中一起发布。

它将PHP编译产生的字节码以及数据缓存到共享内存中, 在每次请求,从缓存中直接读取编译后的opcode,进行执行。

通过节省脚本的编译过程,提高PHP的运行效率。

如果正在使用APC扩展,做同样的工作,现在强烈推荐OPCache来代替,尤其是PHP7中。

4.1 OPCode 缓存

Opcache 会缓存OPCode以及如下内容:

  • PHP脚本涉及到的函数
  • PHP脚本中定义的Class
  • PHP脚本文件路径
  • PHP脚本OPArray
  • PHP脚本自身结构/内容

4.2 Interned String 缓存

首先我们需要理解,什么是 Interned String?

在PHP5.4的时候, 引入了Interned String机制, 用于优化PHP对字符串的存储和处理。

尤其是处理大块的字符串,比如PHP doces时,Interned String 可以优化内存。

Interned String 缓存的内容包括: 变量名称、类名、方法名、字符串、注释等。

在PHP-FPM模式中,Interned String 缓存字符,仅限于Worker 进程内部。

而缓存到OPCache中,那么Worker进程之间可以使用 Interned String 缓存的字符串,节省内存。

我们需要注意一个事情,在PHP开发中,一般会有大段的注释,也会被缓存到OPCache中。

可以通过php.ini的配置,关闭注释的缓存。

但是,像Zend Framework等框架中,会引用注释,所以,是否关闭注释的缓存,需要区别对待。

5. OPCache 更新策略

是缓存,都存在过期,以及更新策略等。

而OPCache的更新策略非常简单,到期数据置为Wasted,达到设定值,清空缓存,重建缓存。

这里需要注意:在高流量的场景下,重建缓存是一件非常耗费资源的事儿。

OPCache 在创建缓存时并不会阻止其他进程读取。

这会导致大量进程反复新建缓存。所以,不要设置OPCache过期时间

每次发布新代码时,都会出现反复新建缓存的情况。如何避免呢?

  • 不要在高峰期发布代码,这是任何情况下都要遵守的规则
  • 代码预热,比如使用脚本批量调PHP 访问URL,或者使用OPCache 暴露的API 如opcache_compile_file() 进行编译缓存

6. OPCache 的配置

6.1 内存配置

  • opcache.preferred_memory_model="mmap" OPcache 首选的内存模块。如果留空,OPcache 会选择适用的模块, 通常情况下,自动选择就可以满足需求。可选值包括: mmapshm, posix 以及 win32
  • opcache.memory_consumption=64 OPcache 的共享内存大小,以兆字节为单位,默认64M
  • opcache.interned_strings_buffer=4 用来存储临时字符串的内存大小,以兆字节为单位,默认4M
  • opcache.max_wasted_percentage=5 浪费内存的上限,以百分比计。 如果达到此上限,那么 OPcache 将产生重新启动续发事件。默认5

6.2 允许缓存的文件数量以及大小

  • opcache.max_accelerated_files=2000 OPcache 哈希表中可存储的脚本文件数量上限。 真实的取值是在质数集合 { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987 } 中找到的第一个大于等于设置值的质数。 设置值取值范围最小值是 200,最大值在 PHP 5.5.6 之前是 100000,PHP 5.5.6 及之后是 1000000。默认值2000
  • opcache.max_file_size=0 以字节为单位的缓存的文件大小上限。设置为 0 表示缓存全部文件。默认值0

6.3 注释相关的缓存

  • opcache.load_comments boolean 如果禁用,则即使文件中包含注释,也不会加载这些注释内容。 本选项可以和 opcache.save_comments 一起使用,以实现按需加载注释内容。
  • opcache.fast_shutdown boolean 如果启用,则会使用快速停止续发事件。 所谓快速停止续发事件是指依赖 Zend 引擎的内存管理模块 一次释放全部请求变量的内存,而不是依次释放每一个已分配的内存块。

6.4 二级缓存的配置

  • opcache.file_cache 配置二级缓存目录并启用二级缓存。 启用二级缓存可以在 SHM 内存满了、服务器重启或者重置 SHM 的时候提高性能。 默认值为空字符串 "",表示禁用基于文件的缓存。
  • opcache.file_cache_only boolean 启用或禁用在共享内存中的 opcode 缓存。
  • opcache.file_cache_consistency_checks boolean 当从文件缓存中加载脚本的时候,是否对文件的校验和进行验证。
  • opcache.file_cache_fallback boolean 在 Windows 平台上,当一个进程无法附加到共享内存的时候, 使用基于文件的缓存,也即:opcache.file_cache_only=1。 需要显示的启用文件缓存。

 推荐学习:《PHP视频教程

以上是深入分析PHP Opcache工作原理的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:awaimai。如有侵权,请联系admin@php.cn删除
PHP与Python:了解差异PHP与Python:了解差异Apr 11, 2025 am 12:15 AM

PHP和Python各有优势,选择应基于项目需求。1.PHP适合web开发,语法简单,执行效率高。2.Python适用于数据科学和机器学习,语法简洁,库丰富。

php:死亡还是简单地适应?php:死亡还是简单地适应?Apr 11, 2025 am 12:13 AM

PHP不是在消亡,而是在不断适应和进化。1)PHP从1994年起经历多次版本迭代,适应新技术趋势。2)目前广泛应用于电子商务、内容管理系统等领域。3)PHP8引入JIT编译器等功能,提升性能和现代化。4)使用OPcache和遵循PSR-12标准可优化性能和代码质量。

PHP的未来:改编和创新PHP的未来:改编和创新Apr 11, 2025 am 12:01 AM

PHP的未来将通过适应新技术趋势和引入创新特性来实现:1)适应云计算、容器化和微服务架构,支持Docker和Kubernetes;2)引入JIT编译器和枚举类型,提升性能和数据处理效率;3)持续优化性能和推广最佳实践。

您什么时候使用特质与PHP中的抽象类或接口?您什么时候使用特质与PHP中的抽象类或接口?Apr 10, 2025 am 09:39 AM

在PHP中,trait适用于需要方法复用但不适合使用继承的情况。1)trait允许在类中复用方法,避免多重继承复杂性。2)使用trait时需注意方法冲突,可通过insteadof和as关键字解决。3)应避免过度使用trait,保持其单一职责,以优化性能和提高代码可维护性。

什么是依赖性注入容器(DIC),为什么在PHP中使用一个?什么是依赖性注入容器(DIC),为什么在PHP中使用一个?Apr 10, 2025 am 09:38 AM

依赖注入容器(DIC)是一种管理和提供对象依赖关系的工具,用于PHP项目中。DIC的主要好处包括:1.解耦,使组件独立,代码易维护和测试;2.灵活性,易替换或修改依赖关系;3.可测试性,方便注入mock对象进行单元测试。

与常规PHP阵列相比,解释SPL SplfixedArray及其性能特征。与常规PHP阵列相比,解释SPL SplfixedArray及其性能特征。Apr 10, 2025 am 09:37 AM

SplFixedArray在PHP中是一种固定大小的数组,适用于需要高性能和低内存使用量的场景。1)它在创建时需指定大小,避免动态调整带来的开销。2)基于C语言数组,直接操作内存,访问速度快。3)适合大规模数据处理和内存敏感环境,但需谨慎使用,因其大小固定。

PHP如何安全地上载文件?PHP如何安全地上载文件?Apr 10, 2025 am 09:37 AM

PHP通过$\_FILES变量处理文件上传,确保安全性的方法包括:1.检查上传错误,2.验证文件类型和大小,3.防止文件覆盖,4.移动文件到永久存储位置。

什么是无效的合并操作员(??)和无效分配运算符(?? =)?什么是无效的合并操作员(??)和无效分配运算符(?? =)?Apr 10, 2025 am 09:33 AM

JavaScript中处理空值可以使用NullCoalescingOperator(??)和NullCoalescingAssignmentOperator(??=)。1.??返回第一个非null或非undefined的操作数。2.??=将变量赋值为右操作数的值,但前提是该变量为null或undefined。这些操作符简化了代码逻辑,提高了可读性和性能。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境