首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >PHP Opcache工作原理

PHP Opcache工作原理

作者头像
猿哥
发布于 2019-11-10 08:29:46
发布于 2019-11-10 08:29:46
1.7K00
代码可运行
举报
文章被收录于专栏:Web技术布道师Web技术布道师
运行总次数:0
代码可运行

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"; }

我们分析一下执行过程:

  1. php初始化执行环节,启动Zend引擎,加载注册的扩展模块
  2. 初始化后读取脚本文件,Zend引擎对脚本文件进行词法分析(lex),语法分析(bison),生成语法树
  3. Zend 引擎编译语法树,生成opcode,
  4. 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_commentsboolean 如果禁用,则即使文件中包含注释,也不会加载这些注释内容。本选项可以和 opcache.save_comments 一起使用,以实现按需加载注释内容。
  • opcache.fast_shutdown boolean 如果启用,则会使用快速停止续发事件。所谓快速停止续发事件是指依赖 Zend 引擎的内存管理模块 一次释放全部请求变量的内存,而不是依次释放每一个已分配的内存块。

6.4 二级缓存的配置

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

7 配置信息

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
zend_extension=opcache.so

; Zend Optimizer + 的开关, 关闭时代码不再优化.
opcache.enable=1

; Determines if Zend OPCache is enabled for the CLI version of PHP
opcache.enable_cli=1


; Zend Optimizer + 共享内存的大小, 总共能够存储多少预编译的 PHP 代码(单位:MB)
; 推荐 128
opcache.memory_consumption=64

; Zend Optimizer + 暂存池中字符串的占内存总量.(单位:MB)
; 推荐 8
opcache.interned_strings_buffer=4


; 最大缓存的文件数目 200100000 之间
; 推荐 4000
opcache.max_accelerated_files=2000

; 内存“浪费”达到此值对应的百分比,就会发起一个重启调度.
opcache.max_wasted_percentage=5

; 开启这条指令, Zend Optimizer + 会自动将当前工作目录的名字追加到脚本键上,
; 以此消除同名文件间的键值命名冲突.关闭这条指令会提升性能,
; 但是会对已存在的应用造成破坏.
opcache.use_cwd=0


; 开启文件时间戳验证
opcache.validate_timestamps=1


; 2s检查一次文件更新 注意:0是一直检查不是关闭
; 推荐 60
opcache.revalidate_freq=2

; 允许或禁止在 include_path 中进行文件搜索的优化
;opcache.revalidate_path=0


; 是否保存文件/函数的注释   如果apigen、Doctrine、 ZF2、 PHPUnit需要文件注释
; 推荐 0
opcache.save_comments=1

; 是否加载文件/函数的注释
;opcache.load_comments=1


; 打开快速关闭, 打开这个在PHP Request Shutdown的时候会收内存的速度会提高
; 推荐 1
opcache.fast_shutdown=1

;允许覆盖文件存在(file_exists等)的优化特性。
;opcache.enable_file_override=0


; 定义启动多少个优化过程
;opcache.optimization_level=0xffffffff


; 启用此Hack可以暂时性的解决”can’t redeclare class”错误.
;opcache.inherited_hack=1

; 启用此Hack可以暂时性的解决”can’t redeclare class”错误.
;opcache.dups_fix=0

; 设置不缓存的黑名单
; 不缓存指定目录下cache_开头的PHP文件. /png/www/example.com/public_html/cache/cache_
;opcache.blacklist_filename=


; 通过文件大小屏除大文件的缓存.默认情况下所有的文件都会被缓存.
;opcache.max_file_size=0

;N 次请求检查一次缓存校验.默认值0表示检查被禁用了.
; 由于计算校验值有损性能,这个指令应当紧紧在开发调试的时候开启.
;opcache.consistency_checks=0

; 从缓存不被访问后,等待多久后(单位为秒)调度重启
;opcache.force_restart_timeout=180

; 错误日志文件名.留空表示使用标准错误输出(stderr).
;opcache.error_log=


; 将错误信息写入到服务器(Apache等)日志
;opcache.log_verbosity_level=1

; 内存共享的首选后台.留空则是让系统选择.
;opcache.preferred_memory_model=

; 防止共享内存在脚本执行期间被意外写入, 仅用于内部调试.
;opcache.protect_memory=0
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PHP技术大全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
PHP Opcache的工作原理
PHP项目中,尤其是在高并发大流量的场景中,如何提升PHP的响应时间,是一项十分重要的工作。
码农编程进阶笔记
2021/07/20
1.4K0
php7性能优化之opcache
最近业务有所增长,随之而来的是慢请求逐渐多了起来,在搜索php性能优化的过程中发现了opcache,相关的文章很多,但是都比较零碎,所以在此做个总结。公司当前使用的PHP版本为php7.x.x。
阿dai学长
2021/07/15
1.6K0
如何更好的使用OPcache实现性能优化
一直知道opcache可以提高PHP性能,但没有具体的关注,更多的利用其他的组件来提升系统的性能。一次无意开启了opcache之后,并随意设置了一些配置。结果导致后面在使用一个项目时,发现项目总是不会读取到最新的代码,而是隔一段时间才会执行到最新代码。排查了很久才想起来开启了opcache,于是对opcache做了一个简单的学习与总结。
兔云小新LM
2021/09/25
1.3K0
如何更好的使用OPcache实现性能优化
详解:PHP加速器配置神器opcache
当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。Opcode cache的目地是避免重复编译,减少CPU和内存开销。如果动态内容的性能瓶颈不在于CPU和内存,而在于I/O操作,比如数据库查询带来的磁盘I/O开销,那么opcode cache的性能提升是非常有限的。但是既然opcode cache能带来CPU和内存开销的降低,这总归是好事。
用户4988085
2021/07/25
2.3K0
[PHP] opcache优化作用
1. PHP 初始化执行环节,启动 Zend 引擎,加载注册的扩展模块。 2. 初始化后读取 PHP 脚本文件,Zend 引擎对 PHP 文件进行词法分析,语法分析,生成语法树。 3. Zend 引擎编译语法树,生成 Opcode。 4. Zend 引擎执行 Opcode,返回执行结果。
唯一Chat
2021/07/29
5440
部署lamp-php安装指南
PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。PHP 独特的语法混合了C、Java、Perl以及PHP自创的语法。它可以比CGI或者Perl更快速地执行动态网页。用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML(标准通用标记语言下的一个应用)文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后代码,编译可以达到加密和优化代码运行,使代码运行更快。
星哥玩云
2022/09/15
1.1K0
Apc缓存Opcode
由于PHP是个解释型语言执行的时候先得把程序读进来,然后由Zend引擎编译成opcode。最后Zend虚拟机顺次执行这些opcode(指令)完成操作。因此我们可 以把这个Opcode缓存起来,下次就能避免重新编译了。 APC缓存作用如下:
黄规速
2022/04/14
6960
Apc缓存Opcode
使用OPCache提升PHP的性能
对于 PHP 这样的解释型语言来说,每次的运行都会将所有的代码进行一次加载解析,这样一方面的好处是代码随时都可以进行热更新修改,因为我们不需要编译。但是这也会带来一个问题,那就是无法承载过大的访问量。毕竟每次加载解析再释放,都会增加 CPU 的负担,通常一台 8核16G 的服务器在2、3000并发左右 CPU 就能达到60%以上的使用率。而且如果你使用的是类似于 Laravel 这种大型的框架,效率将更加低下。这个时候,我们通常会通过增加服务器数量来做负载均衡,从而达到减轻服务器压力的效果。不过,这样做的成本又会增加许多。那么,有没有什么优化的方案呢?
硬核项目经理
2020/08/13
1.1K0
PHP-FPM 性能配置优化
php-fpm 全称是 PHP FastCGI Process Manager 的简称,从名字可得知,是一个 FastCGI 的管理器。
南山竹
2024/06/12
3530
PHP-FPM 性能配置优化
PHP码农在Golang压力下的生存之道-PHP性能优化实践
随着国内Golang的火爆,phper的生存压力越来越大,在一次内部技术讨论中,gopher甚至提出,要什么php,写php的全部开掉,唉,码农何苦为难码农。 本文试图寻找一种有效实践,减少php web程序和golang之间的性能差距,摆脱php在公司往后只能写后台的悲惨命运。 做优化的思路 1、了解php语言特性 2、了解php的执行过程 3、压测分析性能 语言特性 PHP被称为脚本语言或解释型语言,它没有被直接编译为机器指令,而是编译为一种中间代码的形式,无法直接在CPU上执行。 所以PHP的执行需要
架构师刀哥
2018/03/20
2.4K0
编译安装PHP8.0测试版开启Opcache JIT
PHP已经进入了PHP8.0的测试研发阶段,其中就包括万众期待的PHP JIT新特性,这里我们尝新编译安装PHP8.0,并试着开启opcache中的JIT
Zach
2020/07/23
2.5K0
php安全配置记录和常见错误梳理
通常部署完php环境后会进行一些安全设置,除了熟悉各种php漏洞外,还可以通过配置php.ini来加固PHP的运行环境,PHP官方也曾经多次修改php.ini的默认设置。 下面对php.ini中一些安全相关参数的配置进行说明 register_globals 当register_globals = ON时,PHP不知道变量从何而来,也容易出现一些变量覆盖的问题。因此从最佳实践的角度,强烈建议设置 register_globals = OFF,这也是PHP新版本中的默认设置。 open_basedirope
洗尽了浮华
2018/01/22
2.3K0
lnmp 开启 Opcache 脚本缓存提高 php 性能
lnmp 开启 Opcache 脚本缓存可以提高 php 运行性能,进而提高整体服务器的运行效率。Opcache 是 Zend 开发的闭源但可以免费使用的 PHP 优化加速组件。今天魏艾斯博客尝试开启这个组件,并希望能够提高 php 性能,因为是第一次尝试,后面经过一段时间服务器运行后再来汇报结果。
魏艾斯博客www.vpsss.net
2018/06/28
1.6K0
lnmp 开启 Opcache 脚本缓存提高 php 性能
如何正确发布PHP代码
几乎每一个 PHP 程序员都发布过代码,可能是通过 ftp 或者 rsync 同步的,也可能是通过 svn 或者 git 更新的。一个活跃的项目可能每天都要发布若干次代码,但是现实却是很少有人注意其中的细节,实际上这里面有好多坑,很可能你就在坑中却浑然不知。
LA0WAN9
2021/12/14
4.5K0
如何正确发布PHP代码
Nginx工作原理和优化总结。
NGINX以高性能的负载均衡器,缓存,和web服务器闻名,驱动了全球超过 40% 最繁忙的网站。在大多数场景下,默认的 NGINX 和 Linux 设置可以很好的工作,但要达到最佳性能,有些时候必须做些调整。首先我们先了解其工作原理。
黄规速
2022/04/14
1.3K0
Nginx工作原理和优化总结。
CentOS 7.5 + PHP 5.6.36 + Nginx 1.14.0 配置笔记
Nginx 配置文件主要分成四部分:main(全局设置)、server(主机设置)、upstream(上游服务器设置,主要为反向代理、负载均衡相关配置)和 location(URL匹配特定位置后的设置),每部分包含若干个指令。main 部分设置的指令将影响其它所有部分的设置;server 部分的指令主要用于指定虚拟主机域名、IP 和端口;upstream 的指令用于设置一系列的后端服务器,设置反向代理及后端服务器的负载均衡;location 部分用于匹配网页位置(比如,根目录“/”,“/images”,等等)。他们之间的关系式:server 继承 main,location 继承 server;upstream 既不会继承指令也不会被继承,它有自己的特殊指令,不需要在其他地方的应用。
赵达
2018/07/16
1.5K0
nginx+php-fpm工作原理
官方手册:FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。 它的功能包括:
猿哥
2020/03/12
2K0
[笔记] 使用 opcache 优化生产环境PHP
OPcache 通过将 PHP 脚本预编译的字节码存储到共享内存中来提升 PHP 的性能, 存储预编译字节码的好处就是 省去了每次加载和解析 PHP 脚本的开销。
码农编程进阶笔记
2021/07/20
9420
SWOOLE之代码热更新实现_持续的思考 转
本人参与的swoole项目有幸被很多朋友使用,我也大力向周边的一些朋友推荐,随着swoole的版本迭代更新,已经足够稳定了,在阿里,腾讯,yy等各大公司都有着使用,也有很多游戏圈里的朋友也在使用,这些朋友经常会提到一个问题,每次代码更新还需要停止服务,然后重新启动,来达到更新代码,然而这种做法,是比较粗暴的。其实swoole里提供reload的特性,完全支持代码的热更新。
domain0
2018/08/02
1.1K0
php-fpm开启opcache缓存
比较奇怪的是今天的访问量到了500以下,想测试下是哪个地区无法访问,结果打开测速网站,网站直接挂了,所有地区全红,cpu内存跑满。于是想着优化下php的执行,开启代码缓存:
obaby
2023/03/27
2.2K0
php-fpm开启opcache缓存
相关推荐
PHP Opcache的工作原理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档