OPCACHE[实战系列]

简述

字节码缓存不是PHP的新特性,有很多独立的第三方扩展实现了字节码缓存,例如APC,eAccelerator等,从PHP5.5开始内置了字节码缓存功能,名为Zend Opcache
开启字节码缓存之后,PHP解释器不用每次都读取,解析,编译PHP代码,直接从共享内存中读取opcode(字节码),极大地提升应用性能

环境

  • Ubuntu 20.04.5 LTS
  • PHP 8.2.5
  • Nginx 1.18.0
  • composer 2.5.5
  • laravel v10.8.0
  • phpfpm配置
    pm = dynamic
    pm.max_children = 200
    pm.start_servers = 50
    pm.min_spare_servers = 50
    pm.max_spare_servers = 100
    ;pm.max_spawn_rate = 32
    ;pm.process_idle_timeout = 10s;
    ;pm.max_requests = 500

安装php8.2

# 添加PHP8.2 PPA源
# add-apt-repository ppa:ondrej/php
# apt-get -y install php8.2 
# apt-get -y install php8.2-fpm  
# apt-get -y install php8.2-opcache 
# apt-get -y install php8.2-dom 
# apt-get -y install php8.2-curl

安装laravel

# composer create-project laravel/laravel example-app
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PhotoController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
            // 引入的文件总数 469个
            echo "Hello World!";
            die;
    }
}

第一次压测 没开Opcache

这里用的压测工具: github.com/link1st/go-stress-testi...

# ./go-stress-testing-linux -c 50 -n 6 -u http://192.168.6.32/photos/

 开始启动  并发数:50 请求数:6 请求参数: 
request:
 form:http 
 url:http://192.168.6.32/photos/ 
 method:GET 
 headers:map[Content-Type:application/x-www-form-urlencoded; charset=utf-8] 
 data: 
 verify:statusCode 
 timeout:30s 
 debug:false 
 http2.0false 
 keepalive:false 
 maxCon:1 


─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
 耗时│ 并发数│ 成功数│ 失败数│   qps  │最长耗时│最短耗时│平均耗时│下载字节│字节每秒│ 状态码
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────
   1s│     3434057.96990.05682.80862.72408407200:34
   2s│     5099057.011173.19682.80877.021,188593200:99
   3s│     50154058.881173.19647.19849.231,848615200:154
   4s│     50210059.451173.19647.19840.992,520629200:210
   5s│     50300061.911173.19418.52807.673,600727200:300


*************************  结果 stat  ****************************
处理协程数量: 50
请求总数(并发数*请求数 -c * -n): 300 总请求时间: 4.946 秒 successNum: 300 failureNum: 0
tp90: 963.000
tp95: 1020.000
tp99: 1134.000
*************************  结果 end   ****************************

推荐配置

opcache.enable = 1
设置为 1,开启 Opcache 功能。

opcache.validate_timestamps=0
设置为1表示将根据您的 opcache.revalidate_freq 值检查文件时间戳判断文件有没有更改
生产环境中配置为0,生产环境不需要验证文件变动,每次更新部署代码的时候,重启fpm即可,systemctl restart php8.2-fpm.service或者kill -SIGUSR2 pid
顺便解决了上代码的时候文件新旧混合的问题,就是说你要上100个文件,上传完之前,总会出现50个新文件,50个旧文件的时刻,可能会发生一些不愉快的结果
其实开发环境也不太需要用到opcache,所以这个值无脑设置为0

opcache.revalidate_freq=0
当validate_timestamps=1时这个设置才有用
opcache缓存时间,设置为0表示每次都要检查校验文件时间戳判断文件有没有改变,这里会用到系统调用stat
当validate_timestamps=0时,这个值不需要设置

opcache.memory_consumption=128
可以使用函数 opcache_get_status() 来了解 opcache 消耗了多少内存以及是否需要增加数量
也可以在phpinfo()查看缓存详情
OPCACHE[实战系列]
默认值64MB,这里设置为128MB

opcache.interned_strings_buffer=16
在php-fpm进程组之间使用16MB共享内存来存储公共字符串,比如很几百个类都有个字符串变量值为hello world,启用这个选项后,只需要在共享内存里面存一次hello world,变量通过指针指向这个内存区域,算是一个优化项,建议打开
默认值8MB, 这里设置为16MB

opcache.max_accelerated_files=10000
控制opcache最多可以在内存中保存多少个 PHP 文件,使用以下命令快速计算代码库中的文件数。

$ find . -type f -print | grep php | wc -l
7183

laravel10的文件7000多个,设置为10000以防万一

opcache.fast_shutdown = 1
如果启用,将使用快速关闭序列,它不会释放每个分配的块,而是依赖 Zend Engine 内存管理器来释放整个请求变量集。
该指令已在 PHP 7.2.0 中删除。快速关闭序列的一个变体已集成到 PHP 中,如果可能,将自动使用。

第二次压测 开启Opcache

# ./go-stress-testing-linux -c 50 -n 6 -u http://192.168.6.32/photos/

 开始启动  并发数:50 请求数:6 请求参数: 
request:
 form:http 
 url:http://192.168.6.32/photos/ 
 method:GET 
 headers:map[Content-Type:application/x-www-form-urlencoded; charset=utf-8] 
 data: 
 verify:statusCode 
 timeout:30s 
 debug:false 
 http2.0false 
 keepalive:false 
 maxCon:1 


─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
 耗时│ 并发数│ 成功数│ 失败数│   qps  │最长耗时│最短耗时│平均耗时│下载字节│字节每秒│ 状态码
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────
   0s│     503000849.37145.045.3258.873,6009,228200:300


*************************  结果 stat  ****************************
处理协程数量: 50
请求总数(并发数*请求数 -c * -n): 300 总请求时间: 0.390 秒 successNum: 300 failureNum: 0
tp90: 87.000
tp95: 98.000
tp99: 138.000
*************************  结果 end   ****************************

结论

没开Opcache之前, 300 总请求时间: 4.946 秒
打开Opcache之后, 300 总请求时间: 0.390 秒
想了下,主要时压测接口只输出了Hello World! 差别才这么夸张
正常的接口IO会花费固定的时间,opcache对IO没有加速作用

推荐生产环境配置

opcache.enable = 1
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.memory_consumption=128 
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.fast_shutdown = 1 //PHP7.2之后无需再配

开发环境不推荐打开,不然可能会被同事追着打!

原理 有空再看

blog.jpauli.tech/2015-03-05-opcache...

本作品采用《CC 协议》,转载必须注明作者和本文链接
遇强则强,太强另说
讨论数量: 1

:+1: :+1: :+1: :+1: :+1: :+1: :+1:

11个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!