Trả lời nhanh: Tinh chỉnh PHP-FPM chỉ xoay quanh một phép tính: lấy phần RAM dành cho PHP chia cho mức tiêu thụ trung bình của một tiến trình, ra số tiến trình tối đa. Đặt cao hơn con số đó thì lúc cao điểm máy hết bộ nhớ và mọi thứ sập cùng lúc, đặt quá thấp thì khách phải xếp hàng chờ dù CPU còn rảnh. Hai việc kèm theo có tác dụng lớn hơn mọi tinh chỉnh khác: bật OPcache và đọc log truy vấn chậm.
Trang web PHP chậm, câu hỏi đầu tiên thường là nên tăng tham số nào. Trả lời trung thực: phần lớn trường hợp nghẽn không nằm ở PHP-FPM mà ở database, còn PHP-FPM chỉ là chỗ hàng chờ dài ra và lộ vấn đề. Nhưng có vài tham số thật sự quan trọng, và đặt sai chúng thì máy chủ sập dưới tải cao thay vì chạy chậm lại một cách có trật tự.
Đo trước khi chỉnh
Bước đầu tiên không phải sửa cấu hình mà là biết một tiến trình PHP của bạn ăn bao nhiêu bộ nhớ:
ps -ylC php-fpm8.3 --sort:rss | awk '{sum+=$8; n++} END {print sum/n/1024 " MB trung binh"}'Con số này khác nhau rất nhiều theo ứng dụng: một trang tĩnh đơn giản có thể chỉ vài chục MB, còn WordPress nhiều plugin hoặc ứng dụng Laravel nặng dễ chạm 80 tới 150MB mỗi tiến trình. Lấy con số của chính bạn, đừng lấy con số trong bài hướng dẫn nào đó trên mạng.
Sau đó tính phần RAM dành cho PHP: tổng RAM trừ đi phần cho hệ điều hành, database, bộ nhớ đệm và máy chủ web. Trên máy 8GB chạy cả MySQL, thường còn khoảng 3 tới 4GB cho PHP là hợp lý.
Đặt số tiến trình
; /etc/php/8.3/fpm/pool.d/www.confpm = dynamicpm.max_children = 30 ; = RAM danh cho PHP chia cho MB moi tien trinhpm.start_servers = 8pm.min_spare_servers = 5pm.max_spare_servers = 12pm.max_requests = 500 ; tai sinh tien trinh de tranh ro ri bo nhoVí dụ tính: 3.500MB dành cho PHP chia cho 115MB mỗi tiến trình ra khoảng 30. Đó là max_children. Hãy làm tròn xuống chứ đừng làm tròn lên, vì lúc cao điểm mức tiêu thụ mỗi tiến trình thường cao hơn trung bình.
Ba kiểu quản lý tiến trình:
- dynamic giữ sẵn một số tiến trình và tăng khi cần. Hợp với đa số trang có lưu lượng đều.
- ondemand chỉ tạo tiến trình khi có yêu cầu, tiết kiệm RAM lúc vắng khách. Hợp với máy nhỏ chạy nhiều trang ít truy cập, đổi lại yêu cầu đầu tiên sau khoảng nghỉ hơi chậm.
- static giữ cố định một số tiến trình. Chỉ hợp khi máy dành riêng cho một ứng dụng và bạn đã biết chính xác tải.
OPcache, thứ đáng làm nhất
; /etc/php/8.3/fpm/conf.d/10-opcache.iniopcache.enable=1opcache.memory_consumption=192opcache.max_accelerated_files=20000opcache.validate_timestamps=1opcache.revalidate_freq=2OPcache giữ mã đã biên dịch trong bộ nhớ để PHP không phải dịch lại ở mỗi yêu cầu. Đây là tinh chỉnh cho hiệu quả rõ rệt nhất và gần như không có nhược điểm.
Hai tham số hay đặt sai. max_accelerated_files phải lớn hơn tổng số file PHP của dự án, và ứng dụng hiện đại dễ vượt mười nghìn file, nên con số mặc định thường quá nhỏ. Còn validate_timestamps thì để bật khi bạn deploy bằng cách sửa file tại chỗ; chỉ tắt khi quy trình deploy của bạn có bước xóa bộ nhớ đệm, vì tắt mà quên xóa thì code mới không có tác dụng và bạn sẽ gỡ một lỗi không tồn tại.
Tìm nghẽn thật bằng log tiến trình chậm
slowlog = /var/log/php-fpm-cham.logrequest_slowlog_timeout = 5sTừ đó, mọi yêu cầu chạy quá năm giây sẽ được ghi lại kèm dấu vết hàm đang chạy lúc bị bắt. Đây là công cụ chẩn đoán tốt mà PHP-FPM cho bạn, và nó thường chỉ thẳng ra sự thật khó chịu: phần lớn thời gian nằm ở lệnh gọi database hoặc gọi API bên ngoài.
Khi log chỉ về phía database, chỗ cần sửa là truy vấn và chỉ mục chứ không phải tham số PHP. Cách đọc kế hoạch thực thi để tìm truy vấn tệ nằm ở bài đọc EXPLAIN. Tăng số tiến trình trong tình huống này chỉ khiến nhiều truy vấn chậm chạy cùng lúc, làm database còn tệ hơn.
Cùng đó, bật trang trạng thái của PHP-FPM để biết có bao nhiêu tiến trình đang bận và hàng chờ có dài không. Nếu hàng chờ thường xuyên dài trong khi CPU vẫn rảnh, đó là dấu hiệu tiến trình đang ngồi chờ thứ gì đó bên ngoài.
Sai lầm hay gặp
Đặt max_children thật cao cho chắc. Đây là cách nhanh nhất để biến một máy chủ chạy chậm thành một máy chủ chết hẳn. Khi hết RAM, hệ điều hành bắt đầu giết tiến trình, và nạn nhân đầu tiên thường là database.
Chép cấu hình từ bài hướng dẫn khác. Con số phù hợp phụ thuộc vào RAM máy bạn và mức tiêu thụ của chính ứng dụng bạn. Hai thứ đó không ai đoán hộ được.
Quên phần dành cho hệ thống. Database, bộ nhớ đệm, máy chủ web và hệ điều hành đều cần RAM. Chia hết cho PHP là công thức sập vào giờ cao điểm.
Tinh chỉnh PHP khi vấn đề nằm ở đĩa. Ứng dụng đọc ghi nhiều file nhỏ như WordPress chịu ảnh hưởng lớn từ tốc độ ổ đĩa, xem thêm ở bài chẩn đoán WordPress chậm.
Đo trước khi chỉnh, đừng chép cấu hình trên mạng
# 1. Do bo nho trung binh moi tien trinh dang dungps -ylC php-fpm --sort:rss | awk '{sum+=$8; n++} END {print "trung binh", int(sum/n/1024), "MB tren", n, "tien trinh"}' # 2. Bo nho con lai cho PHP sau khi tru he dieu hanh va co so du lieufree -h # 3. Cong thuc: so tien trinh toi da = (bo nho danh cho PHP) / (bo nho moi tien trinh)# Vi du: 2 GB danh cho PHP, moi tien trinh 60 MB -> khoang 33 tien trinh # 4. Xem hien tai co bao nhieu tien trinh va co bi cham tran khonggrep -E "pm.max_children|pm =" /etc/php/*/fpm/pool.d/www.conftail -50 /var/log/php*-fpm.log | grep -i "max_children" # Neu log co dong canh bao cham tran: tang so tien trinh,# nhung phai co du bo nho, neu khong may se het bo nho va chet hanBộ nhớ đệm mã, thứ đáng làm nhất
# Kiem da bat chuaphp -i | grep -E "opcache.enable|opcache.memory_consumption|opcache.max_accelerated_files" # Gia tri goi y cho trang WordPress hoac Laravel co nhieu file:# opcache.enable=1# opcache.memory_consumption=256# opcache.max_accelerated_files=20000# opcache.validate_timestamps=1 (dat 0 tren production, nho xoa cache khi trien khai) # Sau khi chinhsystemctl restart php*-fpmphp -i | grep opcache.enableĐây là thay đổi cho hiệu quả lớn nhất trong toàn bộ việc tinh chỉnh, và cũng là thứ hay bị bỏ qua nhất. Với trang có hàng nghìn tệp mã, bật nó cắt được phần lớn thời gian xử lý mỗi lượt truy cập.
Ba sai lầm hay gặp
- Đặt số tiến trình quá cao theo cấu hình chép trên mạng. Khi tải cao, máy hết bộ nhớ và chết hẳn thay vì chỉ chậm. Chậm còn phục vụ được, chết thì không.
- Chỉnh số tiến trình mà không bật bộ nhớ đệm mã. Làm ngược thứ tự, tốn công mà hiệu quả thấp.
- Không bật nhật ký tiến trình chậm. Đây là công cụ duy nhất cho biết đoạn mã nào đang treo, và nó chỉ cần một dòng cấu hình.
Câu hỏi thường gặp
max_children nên đặt bao nhiêu?
Lấy phần RAM dành riêng cho PHP chia cho mức tiêu thụ trung bình một tiến trình của chính ứng dụng bạn, rồi làm tròn xuống. Không có con số chung vì mức tiêu thụ giữa các ứng dụng chênh nhau nhiều lần.
Tăng số tiến trình có làm trang nhanh hơn không?
Chỉ khi nghẽn thật sự là thiếu tiến trình, tức là hàng chờ dài trong khi CPU và database vẫn rảnh. Nếu nghẽn nằm ở truy vấn chậm thì tăng tiến trình chỉ làm nhiều truy vấn chậm chạy song song và mọi thứ tệ hơn.
Nên dùng dynamic hay ondemand?
Dynamic cho trang có lưu lượng đều vì luôn có sẵn tiến trình phục vụ ngay. Ondemand cho máy nhỏ chạy nhiều trang ít khách vì tiết kiệm RAM lúc vắng, chấp nhận yêu cầu đầu tiên sau khoảng nghỉ chậm hơn chút.
OPcache có cần xóa mỗi lần deploy không?
Nếu để validate_timestamps bật thì PHP tự nhận file mới sau vài giây, không cần làm gì. Nếu tắt để chạy nhanh hơn thì bắt buộc phải có bước xóa bộ nhớ đệm trong script deploy, nếu không code mới sẽ không chạy.
