簡述
字節(jié)碼緩存不是PHP的新特性,有很多獨(dú)立的第三方擴(kuò)展實(shí)現(xiàn)了字節(jié)碼緩存,例如APC,eAccelerator等,從PHP5.5開始內(nèi)置了字節(jié)碼緩存功能,名為Zend Opcache
開啟字節(jié)碼緩存之后,PHP解釋器不用每次都讀取,解析,編譯PHP代碼,直接從共享內(nèi)存中讀取opcode(字節(jié)碼),極大地提升應(yīng)用性能
環(huán)境
- 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()
{
// 引入的文件總數(shù) 469個(gè)
`echo` "Hello World!";
die;
}
}
第一次壓測 沒開Opcache
這里用的壓測工具: https://github.com/link1st/go-stress-testing
# ./go-stress-testing-linux -c 50 -n 6 -u http://192.168.6.32/photos/
開始啟動 并發(fā)數(shù):50 請求數(shù):6 請求參數(shù):
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.0:false
keepalive:false
maxCon:1
─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
耗時(shí)│ 并發(fā)數(shù)│ 成功數(shù)│ 失敗數(shù)│ qps │最長耗時(shí)│最短耗時(shí)│平均耗時(shí)│下載字節(jié)│字節(jié)每秒│ 狀態(tài)碼
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────
1s│ 34│ 34│ 0│ 57.96│ 990.05│ 682.80│ 862.72│ 408│ 407│200:34
2s│ 50│ 99│ 0│ 57.01│ 1173.19│ 682.80│ 877.02│ 1,188│ 593│200:99
3s│ 50│ 154│ 0│ 58.88│ 1173.19│ 647.19│ 849.23│ 1,848│ 615│200:154
4s│ 50│ 210│ 0│ 59.45│ 1173.19│ 647.19│ 840.99│ 2,520│ 629│200:210
5s│ 50│ 300│ 0│ 61.91│ 1173.19│ 418.52│ 807.67│ 3,600│ 727│200:300
************************* 結(jié)果 stat ****************************
處理協(xié)程數(shù)量: 50
請求總數(shù)(并發(fā)數(shù)*請求數(shù) -c * -n): 300 總請求時(shí)間: 4.946 秒 successNum: 300 failureNum: 0
tp90: 963.000
tp95: 1020.000
tp99: 1134.000
************************* 結(jié)果 end ****************************
推薦配置
opcache.enable = 1
設(shè)置為 1,開啟 Opcache 功能。
opcache.validate_timestamps=0
設(shè)置為1表示將根據(jù)您的 opcache.revalidate_freq 值檢查文件時(shí)間戳判斷文件有沒有更改
生產(chǎn)環(huán)境中配置為0,生產(chǎn)環(huán)境不需要驗(yàn)證文件變動,每次更新部署代碼的時(shí)候,重啟fpm即可,systemctl restart php8.2-fpm.service
或者kill -SIGUSR2 pid
順便解決了上代碼的時(shí)候文件新舊混合的問題,就是說你要上100個(gè)文件,上傳完之前,總會出現(xiàn)50個(gè)新文件,50個(gè)舊文件的時(shí)刻,可能會發(fā)生一些不愉快的結(jié)果
其實(shí)開發(fā)環(huán)境也不太需要用到opcache,所以這個(gè)值無腦設(shè)置為0
opcache.revalidate_freq=0
當(dāng)validate_timestamps=1時(shí)這個(gè)設(shè)置才有用
opcache緩存時(shí)間,設(shè)置為0表示每次都要檢查校驗(yàn)文件時(shí)間戳判斷文件有沒有改變,這里會用到系統(tǒng)調(diào)用stat
當(dāng)validate_timestamps=0時(shí),這個(gè)值不需要設(shè)置
opcache.memory_consumption=128
可以使用函數(shù) opcache_get_status() 來了解 opcache 消耗了多少內(nèi)存以及是否需要增加數(shù)量
也可以在phpinfo
()查看緩存詳情
默認(rèn)值64MB,這里設(shè)置為128MB
opcache.interned_strings_buffer=16
在php-fpm進(jìn)程組之間使用16MB共享內(nèi)存來存儲公共字符串,比如很幾百個(gè)類都有個(gè)字符串變量值為hello world
,啟用這個(gè)選項(xiàng)后,只需要在共享內(nèi)存里面存一次hello world
,變量通過指針指向這個(gè)內(nèi)存區(qū)域,算是一個(gè)優(yōu)化項(xiàng),建議打開
默認(rèn)值8MB, 這里設(shè)置為16MB
opcache.max_accelerated_files=10000
控制opcache最多可以在內(nèi)存中保存多少個(gè) PHP 文件,使用以下命令快速計(jì)算代碼庫中的文件數(shù)赖草。
$ find . -type f -print | grep php | wc -l
7183
laravel10的文件7000多個(gè),設(shè)置為10000以防萬一
opcache.fast_shutdown = 1
如果啟用学少,將使用快速關(guān)閉序列,它不會釋放每個(gè)分配的塊秧骑,而是依賴 Zend Engine 內(nèi)存管理器來釋放整個(gè)請求變量集版确。
該指令已在 PHP 7.2.0 中刪除『跽郏快速關(guān)閉序列的一個(gè)變體已集成到 PHP 中绒疗,如果可能,將自動使用骂澄。
第二次壓測 開啟Opcache
# ./go-stress-testing-linux -c 50 -n 6 -u http://192.168.6.32/photos/
開始啟動 并發(fā)數(shù):50 請求數(shù):6 請求參數(shù):
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.0:false
keepalive:false
maxCon:1
─────┬───────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
耗時(shí)│ 并發(fā)數(shù)│ 成功數(shù)│ 失敗數(shù)│ qps │最長耗時(shí)│最短耗時(shí)│平均耗時(shí)│下載字節(jié)│字節(jié)每秒│ 狀態(tài)碼
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼────────
0s│ 50│ 300│ 0│ 849.37│ 145.04│ 5.32│ 58.87│ 3,600│ 9,228│200:300
************************* 結(jié)果 stat ****************************
處理協(xié)程數(shù)量: 50
請求總數(shù)(并發(fā)數(shù)*請求數(shù) -c * -n): 300 總請求時(shí)間: 0.390 秒 successNum: 300 failureNum: 0
tp90: 87.000
tp95: 98.000
tp99: 138.000
************************* 結(jié)果 end ****************************
結(jié)論
沒開Opcache之前, 300 總請求時(shí)間: 4.946 秒
打開Opcache之后, 300 總請求時(shí)間: 0.390 秒
想了下,主要時(shí)壓測接口只輸出了Hello World! 差別才這么夸張
正常的接口IO會花費(fèi)固定的時(shí)間,opcache對IO沒有加速作用
推薦生產(chǎn)環(huán)境配置
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之后無需再配
開發(fā)環(huán)境不推薦打開,不然可能會被同事追著打!