Vấn đề được gây ra bởi một khóa được đặt bởi trình xử lý phiên PHP. Vì vậy, Magento không rõ ràng khóa một cái gì đó và cố gắng chặn các yêu cầu của quản trị viên, mà gần như là một tác dụng phụ cho mỗi lần lưu trữ phiên dựa trên tệp.
Một khóa ghi đang được đặt trên tệp dữ liệu phiên khi nó được mở bởi yêu cầu ban đầu (chạy dài), khiến yêu cầu thứ hai bị chặn cho đến khi khóa được giải phóng khi nó gọi session_start
vàoMage_Core_Model_Session_Abstract_Varien::start
Đây là 100% tái sản xuất. Tôi đã sử dụng cùng một phương pháp bạn đã làm, thêm một sleep(30)
vào đầuMage_Adminhtml_IndexController::globalSearchAction
Đáng lưu ý là điều này không thể được sao chép nếu bạn đang sử dụng bộ lưu trữ phiên db. Sau khi tôi tìm thấy nguyên nhân gốc, tôi đặt hộp cát thành bộ lưu trữ phiên db và không thể tái tạo vấn đề nữa. Vì vậy, trình xử lý phiên db Magento dường như không sử dụng khóa cấp hàng để khóa ghi phiên. Tôi thấy điều này thú vị, bởi vì nó có khả năng mất dữ liệu phiên vì ứng dụng rõ ràng không chiếm nhiều luồng cho cùng một phiên. Lưu ý cho người đọc: Tôi sẽ không bao giờ sử dụng lưu trữ phiên db trong sản xuất để thử và giải quyết vấn đề này, nó chỉ tốt cho việc quá tải cơ sở dữ liệu MySql của bạn.
Tôi đã không thử tái tạo hành vi bằng các hệ thống lưu trữ phiên dựa trên bộ nhớ như Redis, nhưng tôi đoán là việc khóa các bản ghi trong kho lưu trữ phiên cũng có thể bị bỏ qua.
Có những kỹ thuật có thể được sử dụng để tránh điều này như sử dụng session_write_close
để giải phóng khóa trước khi bạn bắt đầu một công việc dài hạn. Nhưng điều này cũng sẽ ngăn bạn viết vào phiên vì bạn vừa đóng nó. Vì vậy, nó không có khả năng được triển khai dễ dàng trên bảng trong Magento, nhưng có khả năng có thể được triển khai trên các tuyến / bộ điều khiển cụ thể.
Kỹ thuật của tôi để xác định điều này là nguyên nhân gốc là để kích hoạt trình tạo hồ sơ Xdebug và kiểm tra tệp "cacheegrind". Khi yêu cầu thứ hai hoàn thành, tôi đã tải tệp đầu ra (~ 25 MB log) vào MacCallGrind và đi sâu vào dấu vết theo đường dẫn của các cuộc gọi trong đó thời gian bao gồm là 28 giây hoặc lớn hơn. Điều này cuối cùng đã dẫn tôi đến session_start
cuộc gọi mất ~ 28 giây để chạy, cho tôi một điểm tuyệt vời để nghiên cứu.
EDIT: Đối với những người quan tâm, tôi đã đăng một ảnh chụp màn hình của tệp "cacheegrind" được xem trong MacCallGrind trên Twitter.