คู่มือเกมแลค › L12 ฐานข้อมูล
แย่งล็อกบน hot row Hot row lock contention
ID สาเหตุ db-hot-row · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
ถ้าทุกคนพยายามแก้แถวเดียวกัน (โกดังกิลด์, ไอเทมฮิตในตลาดประมูล, ตัวนับของทั้งเซิร์ฟเวอร์) จะได้ล็อกทีละคนเท่านั้น
ทำไม การแก้ไขมากระจุกที่แถวเดียวกันเพราะอีเวนต์หรือไอเทมฮิต → ผลคือ คำขอต้องรอจนกว่าจะได้ล็อก → บนหน้าจอ เทรดไม่สำเร็จ, “โปรดลองใหม่ภายหลัง”, ไทม์เอาต์
- อาการ
- กดไม่ติด/โรลแบ็ค, อินพุตดีเลย์
- ปัจจัย
- การหยุดชะงัก, ความหน่วง
- ใครเจอ
- เฉพาะบางฟีเจอร์
- เกิดเมื่อไร
- ตอนคนแห่มารวมกัน
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
- งานฝั่งทีมพัฒนาเกม
- แบ่งแถว (sharded counter), ทำทรานแซกชันให้สั้น, รวมในหน่วยความจำแล้วเขียนลงทีเดียว
- งานฝั่งทีมอินฟรา
- มอนิเตอร์เวลาและจำนวนครั้งที่รอ row lock เพื่อหาแถวที่มีการแย่งกันมากแล้วแชร์ผล
- ตัวเลขที่ควรรู้
- ถ้าคำขอหนึ่งถือล็อกไว้ 10 ms แถวนั้นจะแก้ได้สูงสุด 100 ครั้งใน 1 วินาที ถ้ามีการเรียกไปกลับเซิร์ฟเวอร์อื่นแทรกอยู่ในทรานแซกชัน ก็จะลดลงไปอีกตามเวลานั้น
- บนกราฟ
- สูงตามจำนวนคนและโหลด · จำนวนและเวลารอ row lock
- จุดที่ต้องดู
- MySQL ดูค่าที่เพิ่มขึ้นของ Innodb_row_lock_waits และ Innodb_row_lock_time กับ Innodb_row_lock_current_waits และใช้ sys.innodb_lock_waits หาว่าใครรอใคร PostgreSQL ดูเซสชันที่ wait_event_type เป็น Lock ใน pg_stat_activity และคำขอที่ granted เป็น false ใน pg_locks ถ้าเปิด log_lock_waits (ค่าเริ่มต้นปิด) ล็อกที่รอนานจะถูกบันทึกใน log
- สัญญาณว่าใช่
- การรอล็อกเพิ่มชันตามอีเวนต์และจำนวนผู้เล่น และคำขอที่รออยู่ส่วนใหญ่ชี้ไปที่แถวเดียวกัน (คีย์เดียวกัน) ในตารางเดียวกัน
- สัญญาณว่าไม่ใช่
- การรอกระจายเท่า ๆ กันในหลายตารางและหลายแถว: น่าจะเป็นดิสก์หรือ CPU อิ่มตัว ถ้าเซสชันเดียวถือล็อกไว้นานไม่ปล่อย ให้ดูทรานแซกชันที่เปิดทิ้งไว้นาน (db-long-tx)
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
แหล่งอ้างอิง
- InnoDB Locking MySQL
เมื่อทรานแซกชันหนึ่งล็อกแถว (index record) ไว้ ทรานแซกชันอื่นจะแก้แถวนั้นไม่ได้และต้องรอ - How to Minimize and Handle Deadlocks MySQL
คำแนะนำให้ทำทรานแซกชันให้เล็กและสั้น และ commit ทันทีหลังแก้ข้อมูลที่เกี่ยวข้องเพื่อลดการชนกัน - Server Status Variables MySQL
ดูจำนวนครั้งและเวลาที่รอ row lock จาก Innodb_row_lock_waits และ Innodb_row_lock_time และจำนวนที่กำลังรออยู่จาก Innodb_row_lock_current_waits - The innodb_lock_waits and x$innodb_lock_waits Views MySQL
คิวรีที่รออยู่ (waiting_query), เซสชันที่ขวางอยู่ (blocking_pid) และเวลาที่รอ (wait_age) - The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
wait_event_type ของ pg_stat_activity: ถ้าเป็น Lock แปลว่ากำลังรอ heavyweight lock - pg_locks (PostgreSQL Documentation) PostgreSQL
ถ้า granted เป็น false แปลว่าโปรเซสนั้นกำลังรอให้ได้ล็อก - Error Reporting and Logging (PostgreSQL Documentation) PostgreSQL
log_lock_waits: บันทึก log เมื่อรอล็อกนานกว่า deadlock_timeout, ค่าเริ่มต้นปิด
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: L12 ฐานข้อมูล
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (กดไม่ติด/โรลแบ็ค)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง