Cách tối ưu PHP-FPM

Tác giả Network Engineer, T.Tư 17, 2024, 10:45:38 SÁNG

« Chủ đề trước - Chủ đề tiếp »

0 Thành viên và 2 Khách đang xem chủ đề.

PHP-FPM (hoặc Trình quản lý tiến trình nhanh) cung cấp một số lợi thế so với mod_php, trong đó có hai ưu điểm đáng chú ý nhất là nó linh hoạt hơn trong việc cấu hình và hiện là chế độ chạy PHP ưa thích của nhiều người trong cộng đồng. Tuy nhiên, nếu bạn đang sử dụng cài đặt cấu hình mặc định của trình quản lý gói thì có thể bạn sẽ không tận dụng được tối đa tính năng này.


Trong bài đăng này, tôi sẽ đưa ra một cái nhìn tổng quan ngắn gọn về cách cải thiện hiệu suất của PHP-FPM, bằng cách thảo luận về ba loại trình quản lý tiến trình của PHP-FPM và loại nào phù hợp nhất để sử dụng trong trường hợp nào.

PHP-FPM có thể sử dụng một trong ba loại quản lý tiến trình :

  • Static
  • Dynamic
  • Ondemand

Chúng ta hãy xem xét từng chi tiết một chút.

1. Static

Tĩnh đảm bảo một số lượng tiến trình con cố định luôn có sẵn để xử lý các yêu cầu của người dùng. Điều này được thiết lập với pm.max_children. Ở chế độ này, các yêu cầu không cần đợi quá trình mới khởi động, điều này khiến đây là cách tiếp cận nhanh nhất.

Giả sử rằng bạn muốn sử dụng cấu hình tĩnh với 10 tiến trình con luôn có sẵn, bạn sẽ định cấu hình nó trong /etc/php/7.2/fpm/pool.d/www.conf (giả sử bạn đang sử dụng tệp cấu hình mặc định của PHP-FPM của Debian/Ubunut) như sau:

Mã nguồn [Chọn]
pm = static
pm.max_children = 10

Để xem thay đổi cấu hình có hiệu quả hay không, sau khi khởi động lại PHP-FPM, hãy chạy pstree -c -H <PHP-FPM process id> -S <PHP-FPM process id>. Điều này sẽ cho thấy có mười tiến trình có sẵn, như trong ví dụ bên dưới.

Mã nguồn [Chọn]
php-fpm7.2-+-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            |-php-fpm7.2            -php-fpm7.2
2. Dynamic

Trong chế độ này, PHP-FPM quản lý động số lượng tiến trình con có sẵn và đảm bảo rằng luôn có ít nhất một tiến trình con.

Cấu hình này sử dụng năm tùy chọn cấu hình; đó là:

  • pm.max_children: Số lượng tiến trình con tối đa được phép sinh ra.
  • pm.start_servers: Số lượng tiến trình con sẽ bắt đầu khi PHP-FPM khởi động.
  • pm.min_spare_servers: Số lượng tối thiểu các tiến trình con nhàn rỗi mà PHP-FPM sẽ tạo. Nhiều hơn được tạo ra nếu có ít hơn con số này.
  • pm.max_spare_servers: Số lượng tiến trình con nhàn rỗi tối đa mà PHP-FPM sẽ tạo. Nếu có sẵn nhiều tiến trình con hơn giá trị này thì một số tiến trình con sẽ bị loại bỏ.
  • pm.process_idle_timeout: Thời gian nhàn rỗi, tính bằng giây, sau đó một tiến trình con sẽ bị hủy.

Bây giờ phần thú vị đã đến; làm thế nào để bạn tính toán các giá trị cho từng cài đặt? Sebastian Buckpesch  đưa ra công thức sau:


Chúng ta cũng cần đặt pm.process_idle_timeout, là số giây sau đó một tiến trình nhàn rỗi sẽ bị hủy.

Giả sử máy chủ của Chúng ta có hai CPU, mỗi CPU có bốn lõi và RAM 8GB. Nếu Chúng ta giả sử rằng Linux và các trình nền liên quan đang sử dụng khoảng 2GB (sử dụng free -hlđể có giá trị cụ thể hơn), thì Chúng ta còn lại khoảng 6192 MB.

Bây giờ, mỗi tiến trình sử dụng bao nhiêu bộ nhớ? Để tính toán điều đó, có một tập lệnh Python có tên ps_mem.py. Sau khi chạy nó, sử dụng sudo python ps_mem.py | grep php-fpm, bạn sẽ nhận được kết quả tương tự như sau:

Mã nguồn [Chọn]
28.4 MiB +  33.8 MiB =  62.2 MiB    php-fpm7.2 (11)
Cột đầu tiên là bộ nhớ riêng tư. Cột thứ hai là bộ nhớ dùng chung. Cột thứ ba là tổng RAM được sử dụng. Cột thứ tư là tên tiến trình.

Từ những điều trên, bạn có thể thấy rằng kích thước tiến trình là 62,2MiB. Vì vậy, khi đưa tất cả thông tin đó vào công thức của mình, Chúng ta đi đến kết quả sau:

Mã nguồn [Chọn]
(8192 - 2000) / 62.2
Dựa vào đó, chúng ta đi đến các giá trị cài đặt sau:


Chúng ta sẽ để pm.process_idle_timeoutmặc định là 10s. Giả sử rằng Chúng ta hài lòng với các cài đặt này thì Chúng ta sẽ định cấu hình nó như sau:

  • pm = dynamic
  • pm.max_children = 100
  • pm.start_servers = 32
  • pm.min_spare_servers = 16
  • pm.max_spare_servers = 32
  • pm.max_requests = 200

Bạn cũng có thể thường xuyên sử dụng các công cụ giám sát bộ nhớ để theo dõi lượng bộ nhớ mà ứng dụng của bạn đang sử dụng. Có một số tùy chọn có sẵn cho PHP, bao gồm php-memprof và Tideways.

3. Ondemand

Ondemand có các tiến trình phân nhánh PHP-FPM khi nhận được yêu cầu. Để định cấu hình PHP-FPM để sử dụng nó, chúng ta cần đặt pm thành dynamic và cung cấp các giá trị cho:

  • max_children
  • process_idle_timeout
  • max_requests

max_requests đặt số lượng yêu cầu mà mỗi tiến trình con sẽ thực hiện trước khi hồi sinh. Tài liệu gợi ý rằng cài đặt này hữu ích để khắc phục rò rỉ bộ nhớ.

Giả sử rằng Chúng ta thực hiện các cài đặt tương tự như for dynamic, Chúng ta sẽ định cấu hình nó như sau:

  • pm = ondemand
  • pm.max_children = 100
  • pm.process_idle_timeout = 10s
  • pm.max_requests = 200

4. Cấu hình nào phù hợp với bạn?

Thành thật? Câu trả lời là: " còn tùy ", vì nó luôn phụ thuộc vào loại ứng dụng bạn đang chạy. Tuy nhiên, đây là một số gợi ý về việc nên chọn cấu hình nào.

4.1. Trang web có lưu lượng truy cập thấp

Nếu bạn có trang web có lưu lượng truy cập thấp, chẳng hạn như trang web lưu trữ bảng điều khiển phụ trợ, chẳng hạn như cPanel, thì hãy sử dụng Ondemand. Bộ nhớ sẽ được lưu lại vì các tiến trình con sẽ chỉ được sinh ra khi chúng cần thiết và bị loại bỏ khi chúng không còn cần thiết nữa. Vì đây là phần phụ trợ nên người dùng có thể đợi thêm một hoặc hai phút nữa trong khi một chuỗi xuất hiện để xử lý yêu cầu của họ.

4.2. Trang web có lưu lượng truy cập cao

Nếu bạn có một trang web có lưu lượng truy cập cao, hãy sử dụng Static và điều chỉnh cài đặt dựa trên nhu cầu của bạn theo thời gian và tài nguyên phần cứng sẵn có của bạn. Có vẻ như là quá mức cần thiết khi có một số lượng lớn các tiến trình con luôn sẵn sàng nhận yêu cầu.

Tuy nhiên, các trang web có lưu lượng truy cập cao cần phản hồi càng nhanh càng tốt. Vì vậy, điều cần thiết là sử dụng static để có đủ số lượng tiến trình con sẵn sàng thực hiện việc đó.

Bằng cách sử dụng Ondemand, các tiến trình con có thể sẽ tiêu tốn quá nhiều bộ nhớ do được sinh ra và bị loại bỏ, đồng thời độ trễ khởi động sẽ ảnh hưởng đến hiệu suất.

Sử dụng Dynamic có thể sẽ không tệ, tùy thuộc vào cấu hình. Tuy nhiên, bạn có thể kết thúc với một cấu hình phản chiếu Static một cách hiệu quả.

5. Sử dụng nhiều nhóm cho Frontend/Backend

Bây giờ là đề xuất cuối cùng: phục vụ giao diện người dùng và phần phụ trợ của trang web của bạn bằng cách sử dụng các nhóm khác nhau. Giả sử bạn có một trang web thương mại điện tử, có thể được cung cấp bởi Magento. Bạn có thể xem ứng dụng này bao gồm hai phần:

  • Giao diện người dùng nơi khách hàng có thể duyệt và mua hàng
  • Phần phụ trợ, nơi nhân viên quản trị quản lý cửa hàng (chẳng hạn như thêm/xóa sản phẩm, danh mục và thẻ cũng như đánh giá xếp hạng)

Khi được xem theo cách này, sẽ hợp lý khi có một nhóm phục vụ giao diện người dùng và một nhóm khác phục vụ phần phụ trợ và định cấu hình từng nhóm một cách thích hợp.

Với giá trị của nó, bạn có thể chia bất kỳ ứng dụng nào thành nhiều phần bằng cách sử dụng chiến lược này, nếu làm như vậy là hợp lý. Đây là cách để làm như vậy.

Trong /etc/php/7.2/fpm/pool.d/www.conf, thêm cấu hình sau:

Mã nguồn [Chọn]
; frontend [frontend] listen = /var/run/php-fpm-frontend.sock user = www-data group = www-data listen.owner = www-data listen.group = www-data pm = static pm.max_children = 5

; backend [backend] listen = /var/run/php-fpm-backend.sock user = www-data group = www-data listen.owner = www-data listen.group = www-data pm = ondemand pm.max_children = 5 pm.process_idle_timeout = 10s

Điều này tạo ra hai nhóm, một cho giao diện người dùng và một cho phần phụ trợ. Cả hai đều có cùng một người dùng và nhóm, nhưng có cấu hình trình quản lý tiến trình khác nhau và được kết nối qua các ổ cắm khác nhau.

Nhóm giao diện người dùng sử dụng cấu hình Static với số lượng tiến trình con tối đa nhỏ. Nhóm phụ trợ sử dụng cấu hình Ondemand, cũng với một số lượng nhỏ cấu hình. Những con số này là tùy ý vì chúng nhằm mục đích làm ví dụ.

Với điều đó đã được lưu, đối với tệp vhost NGINX của bạn, hãy sử dụng cấu hình sau:

Mã nguồn [Chọn]
server {   listen       80;   server_name  test-site.localdomain;   root         /var/www/test-site/public;

  access_log /var/log/nginx/test-site.access.log;   error_log  /var/log/nginx/test-site.error.log error;   index index.php;

  set $fpm_socket "unix:/var/run/php-fpm-frontend.sock";

  if ($uri ~* "^/api/") {       set $fpm_socket "unix:/var/run/php-fpm-backend.sock";   }

  location / {     try_files $uri $uri/ /index.php;

    location ~.php$ {       fastcgi_split_path_info ^(.+.php)(/.+)$;       fastcgi_pass $fpm_socket;       fastcgi_index index.php;       include fastcgi.conf;       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;     }   } }

Điều này tạo ra một cấu hình máy chủ ảo gửi yêu cầu đến nhóm giao diện người dùng hoặc nhóm phụ trợ, dựa trên vị trí được yêu cầu. Mọi yêu cầu sẽ /apiđược gửi đến nhóm phụ trợ và tất cả các yêu cầu khác sẽ được chuyển đến giao diện người dùng.

Đó là phần giới thiệu nhanh về cách điều chỉnh PHP-FPM để có hiệu suất tốt hơn. Chúng ta đã xem xét ba cấu hình trình quản lý tiến trình khác nhau, các cài đặt liên quan của chúng và thảo luận xem mỗi cấu hình có ý nghĩa hay không. Sau đó Chúng ta kết thúc bằng cách xem xét nhóm công nhân.