ปัญหาเกิดจากการล็อคที่วางโดยตัวจัดการเซสชัน PHP ดังนั้นวีโอไอพีจึงไม่ล็อคสิ่งใดไว้อย่างชัดเจนและพยายามบล็อกคำขอของผู้ดูแลระบบ แต่มีผลข้างเคียงต่อการจัดเก็บเซสชันตามไฟล์
ล็อคการเขียนจะถูกวางไว้ในไฟล์ข้อมูลเซสชั่นเมื่อมันถูกเปิดโดยการร้องขอเริ่มต้น (ทำงานนาน) ทำให้การร้องขอที่สองเพื่อบล็อกจนกว่าการล็อคจะถูกปล่อยออกเมื่อมีการโทรsession_start
เข้าMage_Core_Model_Session_Abstract_Varien::start
สามารถทำซ้ำได้ 100% ฉันใช้วิธีการเดียวกับที่คุณทำโดยเพิ่ม a sleep(30)
ไปด้านบนของMage_Adminhtml_IndexController::globalSearchAction
น่าสังเกตว่าสิ่งนี้ไม่สามารถทำซ้ำได้หากคุณใช้ที่เก็บข้อมูลเซสชัน db หลังจากฉันพบสาเหตุที่แท้จริงฉันตั้งค่า sandbox ให้เป็นที่เก็บข้อมูลเซสชัน db และไม่สามารถทำให้เกิดปัญหาอีกต่อไป ดังนั้นตัวจัดการเซสชัน db Magento ดูเหมือนจะไม่ใช้การล็อกระดับแถวเพื่อล็อคการเขียนเซสชัน ฉันพบว่าสิ่งนี้น่าสนใจเพราะมีโอกาสที่จะเกิดการสูญเสียข้อมูลเนื่องจากแอปพลิเคชันนั้นไม่ได้พิจารณาว่ามีหลายเธรดที่เขียนในเซสชันเดียวกัน หมายเหตุสำหรับผู้อ่าน: ฉันจะไม่ใช้ที่เก็บข้อมูลเซสชัน db ในการผลิตเพื่อลองและแก้ไขปัญหานี้เป็นการดีสำหรับการโหลดฐานข้อมูล MySql ของคุณมากเกินไป
ฉันไม่ได้ลองทำซ้ำพฤติกรรมโดยใช้ระบบจัดเก็บข้อมูลเซสชันที่ใช้หน่วยความจำเช่น Redis แต่ฉันเดาว่าการล็อกระเบียนในที่เก็บเซสชันอาจถูกมองข้ามในสิ่งเหล่านี้เช่นกัน
มีเทคนิคที่สามารถใช้เพื่อหลีกเลี่ยงปัญหานี้เช่นการใช้session_write_close
เพื่อปลดล็อคก่อนที่คุณจะเริ่มงานที่ยาวนาน แต่สิ่งนี้จะป้องกันคุณจากการเขียนไปยังเซสชันตั้งแต่คุณเพิ่งปิดไป ดังนั้นจึงไม่น่าจะมีการนำไปใช้อย่างง่ายดายทั่วทั้งกระดานใน Magento แต่สามารถนำไปใช้กับเส้นทาง / คอนโทรลเลอร์ที่เฉพาะเจาะจงได้
เทคนิคของฉันในการตรึงสิ่งนี้เป็นสาเหตุหลักคือการเปิดใช้งานตัวสร้างโปรไฟล์ Xdebug และตรวจสอบไฟล์ "cachegrind" เมื่อคำขอที่สองเสร็จสมบูรณ์ฉันโหลดไฟล์เอาต์พุต (~ 25 MB บันทึก) ลงในMacCallGrindและเจาะลึกลงไปในการติดตามตามเส้นทางการโทรที่เวลารวมเป็น 28 วินาทีหรือมากกว่า ในที่สุดสิ่งนี้ทำให้ฉันsession_start
โทรออกซึ่งใช้เวลาประมาณ 28 วินาทีในการวิ่งซึ่งเป็นจุดที่ดีในการวิจัยจากฉัน
แก้ไข:สำหรับความสนใจฉันโพสต์ภาพหน้าจอของไฟล์ "cachegrind" ที่ดูใน MacCallGrind บน Twitter