Chuyển tới nội dung chính
Version: 4.1

PHP X-Ray

PHP X-Ray (/php/xray) cho biết PHP của một website thực sự đang tiêu tốn thời gian ở đâu.

Nó được xây dựng trên những gì máy chủ đã ghi lại, thay vì trên một profiler mà bạn phải cài. Mọi pool PHP-FPM mà panel này ghi đều đặt request_slowlog_timeout và pm.status_path, nên từ trước đến nay PHP-FPM vẫn luôn ghi call stack của mọi yêu cầu chậm xuống đĩa, và trả lời các câu hỏi về chính các worker của nó.

Hai góc nhìn, trả lời những câu hỏi khác nhau:

  • Live — mỗi worker đang làm gì ngay giây này, và pool đã cạn worker hay chưa. Đó là câu trả lời mà không stack trace nào có thể đưa ra.
  • Slow — các yêu cầu đã vượt ngưỡng và chính xác hàm mà mỗi yêu cầu đang ở bên trong, được gom nhóm để cùng một điểm nghẽn gặp nhiều lần được đọc như một vấn đề thay vì nhiều vấn đề.
  • Cơ sở dữ liệu đang làm gì vào cùng lúc đó — các yêu cầu chậm ở trên được đặt cạnh các truy vấn cơ sở dữ liệu chậm mà DB Governor ghi lại cho cùng tài khoản.
  • Bao nhiêu phần của mỗi yêu cầu chậm là thời gian chờ — theo từng yêu cầu, và chỉ khi quản trị viên đã bật tính năng này cho website. Xem bên dưới.

Khối cơ sở dữ liệu có thể và không thể cho bạn biết gì​

Một cặp có một ý nghĩa: một truy vấn thuộc tài khoản này đang chạy trong khi yêu cầu đó đang chạy. Đó là bằng chứng, không phải chứng minh. Bản ghi tính theo tài khoản, nên một truy vấn từ một yêu cầu khác của tài khoản, hoặc từ một tác vụ cron của nó, có thể rơi vào cùng khoảng thời gian, và sự chồng lấn không thể cho biết bên nào trong hai bên đang chờ bên kia. Vì vậy trang nói "vào cùng lúc", không bao giờ "vì", và khi không có gì chồng lấn, nó nói là không tìm thấy gì thay vì đưa ra truy vấn gần nhất.

Khi bật đo thời gian chờ theo từng yêu cầu cho website, mỗi cặp có thêm một câu: yêu cầu đó có thực sự bị chặn không, trong bao lâu, và truy vấn dài nhất trong khoảng thời gian có cùng độ lớn với thời gian chờ không. Đó là một khẳng định mạnh hơn sự chồng lấn, nhưng vẫn không phải "vì" — xem bên dưới để biết chính xác nó đi được bao xa.

Khoảng thời gian là đoạn mà yêu cầu được biết chắc là đang chạy. PHP-FPM ghi bản ghi đúng lúc yêu cầu vượt request_slowlog_timeout, nên một bản ghi đóng dấu 22:23:33 với ngưỡng 15 giây bảo đảm cho 22:23:18–22:23:33. Yêu cầu có thể đã bắt đầu sớm hơn — đo trên một máy chủ thực, việc kiểm tra của chính FPM trễ hơn ngưỡng của nó bốn giây — nên một truy vấn chỉ chạy trong vài giây đầu của yêu cầu có thể nằm ngoài khoảng thời gian và không được ghép cặp. Đó là chủ ý: mở rộng khoảng thời gian sẽ ghép các truy vấn chưa từng chồng lấn với yêu cầu.

DB Governor ghi lại gì, và bỏ sót gì​

Governor giữ bản ghi (hitechcloudcli dbgovernor slowqueries, mỗi tài khoản một tệp) và điền vào đó trong lượt chạy mỗi phút của bộ hẹn giờ riêng — bộ hẹn giờ mà hitechcloudcli dbgovernor enable cài đặt. Trên máy chủ chưa từng bật DB Governor thì hoàn toàn không có bản ghi: khi đó khối nói rằng governor chưa ghi lại gì cho tài khoản này — đó không phải cùng một khẳng định với "cơ sở dữ liệu đang yên tĩnh", và nên kiểm tra với quản trị viên trước khi hiểu theo nghĩa đó.

Có hai nguồn, và trang cho biết nó đang đọc nguồn nào:

  • sample — những gì governor bắt gặp đang chạy khi nó kiểm tra, mỗi phút một lần. Không cần cấu hình, nhưng một truy vấn bắt đầu và kết thúc giữa hai lần kiểm tra sẽ không để lại dấu vết.

  • slow_log — mọi câu lệnh vượt long_query_time của máy chủ, không có khoảng trống lấy mẫu. Nó cần bật slow-query log của cơ sở dữ liệu, đây là thiết lập toàn máy chủ, nên quản trị viên bật nó một cách có chủ ý:

    hitechcloudcli dbgovernor slowqueries --enable --seconds 2

Các truy vấn mà governor kết thúc khi một tài khoản vượt phần cơ sở dữ liệu của nó cũng được ghi lại, trước khi bị kết thúc.

Bao nhiêu phần của mỗi yêu cầu chậm là thời gian chờ​

Khối này tắt trừ khi quản trị viên bật nó cho website, và nó tự tắt lại sau khoảng thời gian mà họ đã đặt:

hitechcloudcli fpm xray install # once per server
hitechcloudcli fpm xray on example.com --minutes 60
hitechcloudcli fpm xray status
hitechcloudcli fpm xray off example.com

Khi bật, pool PHP của website chạy một shim nhỏ trước mỗi yêu cầu. Shim lấy mẫu yêu cầu theo hai bộ hẹn giờ cùng chu kỳ — một theo đồng hồ thực, một theo thời gian CPU — và chênh lệch tại một dòng mã của bạn là thời gian yêu cầu ở đó mà không tính toán: bị chặn chờ cơ sở dữ liệu, bộ nhớ đệm, một lời gọi HTTP, ổ đĩa. Với yêu cầu đủ chậm để đáng ghi (mặc định trên một giây), nó ghi một bản ghi; với yêu cầu nhanh, nó không ghi gì.

Một bản ghi được ghép với một dòng nhật ký yêu cầu chậm theo worker đã phục vụ nó, script, và thời điểm bắt đầu, kết thúc của chính yêu cầu. Một worker phục vụ một yêu cầu tại một thời điểm, nên việc ghép đó là chính xác chứ không phải có khả năng — điều mà phép nối theo tài khoản và khoảng thời gian ở trên không bao giờ làm được. Bản ghi không có dòng nhật ký tương ứng cũng được hiển thị, kèm đánh dấu: một yêu cầu có thể đủ chậm để đáng ghi mà không vượt ngưỡng riêng của PHP-FPM.

Nó có thể và không thể cho bạn biết gì​

Nó có thể nói: yêu cầu này chạy 19.1 giây, dành 18.4 giây trong đó để chờ thay vì tính toán, và 18.0 giây chờ đó nằm ở dòng 2353 của class-wpdb.php, bên trong wpdb::_do_query.

Nó không thể nói đã chờ cái gì. Profiler thấy dòng trong cùng của mã PHP, không thấy socket bên dưới — một dòng $wpdb->query() và một dòng file_get_contents() trông giống hệt nhau từ đó. Đặc biệt, nó không nêu tên truy vấn. Văn bản câu lệnh không có trong bản ghi này và không thể có: nó nằm bên trong một hàm nội bộ hoàn toàn không phải frame PHP. Khối cơ sở dữ liệu ở trên, với bản ghi của DB Governor, là nơi có các câu lệnh ứng viên; ghép hai thứ lại là việc của người đọc, và trang không bao giờ làm thay họ.

Các số liệu được lấy mẫu, không phải đếm, nên thời gian chờ một hoặc hai chu kỳ lấy mẫu là nhiễu, chỉ thời gian chờ gấp nhiều lần chu kỳ mới là số đo có ý nghĩa. Đó là lý do shim bỏ qua các yêu cầu nhanh: với một yêu cầu chậm ở chu kỳ mặc định 10ms có hàng trăm hoặc hàng nghìn mẫu và các số liệu là đáng tin.

Chi phí​

Đo trên một máy chủ thực (AlmaLinux 10, PHP 8.3, trang chủ WordPress mất khoảng 0.58 giây, mỗi trường hợp chạy năm lần):

giây
tắt shim0.63 0.54 0.58 0.59 0.59
bật shim, chu kỳ 10ms0.66 0.59 0.58 0.56 0.62

Chênh lệch nằm trong biên độ dao động giữa các lần chạy. Dù vậy, nó vẫn không được để bật mãi: khoảng thời gian quản trị viên đặt tự hết hạn, vì một công cụ chẩn đoán không ai nhớ tắt là công cụ chẩn đoán không ai kiểm soát.

Không có ở đâu​

Bộ lấy mẫu được đóng gói cho PHP 7.4 và 8.0 đến 8.5. Chưa có gói cho PHP 8.6, nên website chạy 8.6 không thể có khối này, và fpm xray status cho biết điều đó theo từng phiên bản thay vì thất bại về sau.