Zend OPcache: khái niệm, cách cài đặt và cấu hình, giá trị php.ini và tắt JIT
Zend OPcache là một tiện ích mở rộng của PHP, biên dịch script PHP thành bytecode rồi lưu vào bộ nhớ chia sẻ, nhờ đó bỏ qua bước biên dịch khi chạy lại cùng một tệp. Khi bật JIT trên máy chủ WordPress dùng PHP 8.3 khiến mọi trang báo lỗi 500, máy chủ được khôi phục bằng cách giữ nguyên OPcache và chỉ tắt JIT.
Từ PHP 5.5, OPcache được đóng gói sẵn trong PHP theo mặc định.
1️⃣ Khái niệm Zend OPcache: cache bytecode
Mỗi khi có một yêu cầu, script PHP đi qua ba bước: đọc tệp, biên dịch thành bytecode và thực thi. Khi OPcache hoạt động, từ yêu cầu thứ hai cho cùng một tệp, hai bước đầu biến mất và chỉ còn lại bước thực thi.
Bộ nhớ chia sẻ mà OPcache dùng để lưu bytecode được tất cả worker của PHP-FPM dùng chung. Nếu có nhiều website nối với cùng một PHP-FPM, script của các website đó cũng được lưu trong một bộ nhớ chia sẻ duy nhất.
Thứ OPcache lưu là mã PHP đã biên dịch, nên việc thực thi PHP và truy vấn cơ sở dữ liệu vẫn diễn ra mỗi lần mở trang. Lưu HTML đã tạo xong để bỏ qua hoàn toàn việc thực thi PHP là vai trò của page cache.
2️⃣ Kiểm tra việc cài đặt PHP OPcache
Bạn có thể biết OPcache đã được cài hay chưa ở dòng cuối của kết quả [php -v].
php -vPHP 8.3.22 (cli) (built: Jun 3 2025 17:17:57) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.22, Copyright (c) Zend Technologies
with Zend OPcache v8.3.22, Copyright (c), by Zend TechnologiesNếu không có dòng cuối đó, hãy cài bằng dnf. Tên gói thường là php-opcache; nếu đã cài nhiều phiên bản PHP cùng lúc từ kho Remi thì tên gói có thêm phiên bản, ví dụ php83-php-opcache.
dnf -y install php-opcacheGói php-opcache của kho Remi nạp tiện ích mở rộng bằng dòng [zend_extension=opcache] trong [/etc/php.d/10-opcache.ini]. Sau khi cài, hãy khởi động lại PHP-FPM để OPcache cũng áp dụng cho các yêu cầu web.
3️⃣ Cấu hình OPcache: giá trị php.ini
Cấu hình OPcache có thể nằm ở hai nơi: phần [opcache] của [/etc/php.ini] và [/etc/php.d/10-opcache.ini].
php --iniConfiguration File (php.ini) Path: /etc
Loaded Configuration File: /etc/php.ini
Scan for additional .ini files in: /etc/php.d
Additional .ini files parsed: /etc/php.d/10-opcache.ini,Các tệp trong thư mục php.d được đọc sau php.ini, nên nếu cùng một mục được ghi ở cả hai nơi thì giá trị bên php.d được áp dụng.
Bảng dưới đây cho thấy giá trị mặc định của PHP 8.3 và các giá trị được áp dụng trên máy chủ WordPress đã kiểm tra.
| Hạng mục | Mặc định của PHP 8.3 | Giá trị áp dụng | Ý nghĩa |
|---|---|---|---|
| opcache.enable | 1 | 1 | Dùng OPcache |
| opcache.enable_cli | 0 | 1 | Dùng cả với PHP dòng lệnh (wp-cli, v.v.) |
| opcache.memory_consumption | 128 | 1024 | Bộ nhớ chia sẻ lưu bytecode (MB) |
| opcache.interned_strings_buffer | 8 | 16 | Bộ nhớ chỉ lưu một lần cho các chuỗi giống nhau (MB) |
| opcache.max_accelerated_files | 10000 | 10000 | Giới hạn trên của số khóa có thể cache (giới hạn thực tế là số nguyên tố bằng hoặc lớn hơn giá trị này: 16229 với 10000) |
| opcache.max_wasted_percentage | 5 | 10 | Nếu thiếu bộ nhớ và vùng bị lãng phí vượt tỷ lệ này, cache được xóa và khởi động lại |
| opcache.validate_timestamps | 1 | 1 | Kiểm tra xem tệp có thay đổi không |
| opcache.revalidate_freq | 2 | 60 | Chu kỳ kiểm tra thay đổi của tệp (giây) |
| opcache.jit | tracing | disable | Chế độ JIT (từ PHP 8.4 mặc định là disable) |
| opcache.jit_buffer_size | 0 | 0 | Bộ nhớ của JIT; nếu là 0 thì JIT không hoạt động (từ PHP 8.4 mặc định là 64M) |
Các giá trị đặt trong phần [opcache] của [/etc/php.ini] như bên dưới. Dung lượng bộ nhớ được chọn theo bộ nhớ của máy chủ, còn [opcache.max_accelerated_files] theo số tệp của WordPress.
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=1024
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=10
opcache.validate_timestamps=1
opcache.revalidate_freq=60Nếu đặt lại dòng [zend_extension] vào php.ini, tiện ích mở rộng bị nạp hai lần và xuất hiện cảnh báo [Cannot load Zend OPcache].
Khi [opcache.revalidate_freq] là 60, sau khi sửa tệp PHP, mã cũ vẫn có thể chạy thêm tối đa 60 giây.
Với máy chủ WordPress có tệp PHP thay đổi thường xuyên, hãy để [opcache.validate_timestamps] là 1 để kiểm tra thay đổi của tệp. Giá trị 0 mà tài liệu Symfony khuyên dùng cho máy chủ vận hành phù hợp với máy chủ mà tệp PHP chỉ thay đổi khi triển khai phiên bản mới.
Dù [opcache.validate_timestamps] là 0, khi cập nhật từ màn hình quản trị, chính WordPress sẽ xóa cache của các tệp đã thay đổi. Nhưng nếu cập nhật bằng wp-cli hoặc sửa tệp qua SSH thì mã cũ vẫn chạy cho đến khi PHP-FPM được khởi động lại.
4️⃣ Tắt JIT của OPcache
JIT của PHP 8 là tính năng giúp các tác vụ tốn nhiều phép tính CPU chạy nhanh hơn, nên hiệu quả nhỏ với ứng dụng xử lý yêu cầu web như WordPress. Trong phép đo WordPress được đăng ở PHP JIT RFC cũng vậy, lần chạy bật JIT xử lý 326 yêu cầu mỗi giây còn lần tắt JIT là 315.
JIT được bật trên máy chủ WordPress dùng PHP 8.3.22 bằng [opcache.jit=tracing] và [opcache.jit_buffer_size=128M]. Ba ngày sau, vào ngày yêu cầu dồn dập khiến các worker của PHP-FPM khởi động lại nhiều lần, tất cả các trang đều xảy ra lỗi 500.
Nhật ký lỗi còn lại thông báo [Allowed memory size of 1073741824 bytes exhausted]. Phần [tried to allocate 4295229440 bytes] đi sau là bản ghi về việc cố cấp phát 4GB một lần trong khi giới hạn bộ nhớ của PHP là 1GB. Sau khi tắt JIT, chính các yêu cầu đó đã được xử lý bình thường.
Tắt JIT bằng cách đặt hai dòng dưới đây vào [/etc/php.d/10-opcache.ini]. Dù cấu hình JIT vẫn còn trong [/etc/php.ini], giá trị trong tệp này vẫn được áp dụng.
opcache.jit=disable
opcache.jit_buffer_size=0Trong PHP 8.3, mặc định của [opcache.jit_buffer_size] là 0, nên nếu không đặt riêng thì JIT không hoạt động. Từ PHP 8.4, mặc định của [opcache.jit] cũng là disable.
5️⃣ Áp dụng và kiểm tra cấu hình
Cấu hình đã thay đổi chỉ được áp dụng sau khi khởi động lại PHP-FPM.
systemctl restart php-fpmSau khi khởi động lại, bộ nhớ chia sẻ của OPcache được làm trống và cấp phát lại theo cấu hình mới.
php -i | grep -E '^opcache\.(enable|memory_consumption|revalidate_freq|validate_timestamps|jit) 'opcache.enable => On => On
opcache.jit => disable => disable
opcache.memory_consumption => 1024 => 1024
opcache.revalidate_freq => 60 => 60
opcache.validate_timestamps => On => OnCác giá trị do [php -i] in ra là cấu hình của PHP dòng lệnh. Trên họ RHEL, PHP-FPM cũng đọc cùng các tệp [/etc/php.ini] và [/etc/php.d], nên giá trị giống nhau.
Nếu gọi [opcache_get_status()] trên dòng lệnh, số script đã cache là 0. PHP dòng lệnh tạo bộ nhớ chia sẻ mới mỗi lần chạy, nên mức dùng của PHP-FPM được kiểm tra bằng cách đặt tệp dưới đây vào thư mục tài liệu web rồi mở trong trình duyệt.
<?php
header('Content-Type: text/plain');
$s = opcache_get_status(false);
print_r($s['memory_usage']);
print_r($s['opcache_statistics']);
print_r($s['interned_strings_usage']);
var_dump($s['cache_full']);Nếu [cache_full] là true, bộ nhớ chia sẻ hoặc các khóa đã đầy. Sau khi kiểm tra xong, hãy xóa ngay tệp này.
Trên máy chủ có ba website WordPress dùng chung một PHP-FPM, 317MB trong tổng 1024MB bộ nhớ chia sẻ đang được dùng. Số script đã cache là 3.366 đến 4.222 mỗi website, tổng cộng 11.358.
OPcache lưu script theo đường dẫn thực, còn với tệp được nạp bằng đường dẫn tương đối thì tạo thêm một khóa có gắn thư mục làm việc, nên số khóa nhiều hơn số script. Với 11.358 script, các khóa đã lấp đầy giới hạn 16.229, và bộ đệm chuỗi 16MB cũng không còn chỗ trống.
Khi khóa đầy, script mới không được cache và bị biên dịch ở mỗi yêu cầu. Trong 5 phút 21 giây, số lần cache miss tăng từ 18.408 lên 36.027, nhưng số script đã cache vẫn là 11.358.
Với máy chủ chạy nhiều WordPress hoặc nhiều plugin, hãy đặt [opcache.max_accelerated_files] rộng rãi để giới hạn khóa không bị đầy. Nếu đặt 20000, giới hạn khóa thực tế là 32.531. Nếu bộ đệm chuỗi đã đầy, hãy tăng luôn [opcache.interned_strings_buffer].
🔢 FAQ & nội dung đề xuất
Cache
Cache: định nghĩa và mọi lĩnh vực có dùng cache
Bài phân loại các lĩnh vực dùng cache, gồm OPcache lưu mã PHP đã biên dịch và page cache lưu HTML đã tạo xong.
PHP-FPM
Cảnh báo php-fpm max_children: tìm nguyên nhân trong log trước khi tăng worker
Bài về cách xác định qua nhật ký nguyên nhân của cảnh báo xuất hiện khi các worker PHP-FPM dùng chung bộ nhớ chia sẻ của OPcache đã đầy.
PHP-FPM
PHP-FPM là gì | Cài đặt và cấu hình PHP-FPM
Bài về cách cài đặt PHP-FPM, nơi OPcache hoạt động bên trong, cấu hình pool trong www.conf và cách khởi động lại.
ℹ️ Thông báo tiếp thị liên kết
Nội dung trên trang này có chứa liên kết affiliate (tiếp thị liên kết). Khi khách truy cập mua sản phẩm hoặc dịch vụ qua các liên kết này, trang sẽ nhận hoa hồng từ bên bán. Trong quá trình đó, số tiền người mua phải trả (sẽ giảm khi có chương trình khuyến mãi ↓) không hề tăng lên. Giá, khuyến mãi và tình trạng hàng được đăng theo thời điểm viết bài và có thể khác với thực tế, vì vậy hãy kiểm tra lại lần cuối với bên bán trước khi mua. Việc chọn và đánh giá sản phẩm dựa trên tiêu chí riêng của trang; việc có nhận hoa hồng hay không không ảnh hưởng đến thứ tự giới thiệu hay nội dung đánh giá.