한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

คู่มือเกมแลค › 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)
วิธีตรวจ
ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)

แหล่งอ้างอิง

  1. InnoDB Locking MySQL
    เมื่อทรานแซกชันหนึ่งล็อกแถว (index record) ไว้ ทรานแซกชันอื่นจะแก้แถวนั้นไม่ได้และต้องรอ
  2. How to Minimize and Handle Deadlocks MySQL
    คำแนะนำให้ทำทรานแซกชันให้เล็กและสั้น และ commit ทันทีหลังแก้ข้อมูลที่เกี่ยวข้องเพื่อลดการชนกัน
  3. Server Status Variables MySQL
    ดูจำนวนครั้งและเวลาที่รอ row lock จาก Innodb_row_lock_waits และ Innodb_row_lock_time และจำนวนที่กำลังรออยู่จาก Innodb_row_lock_current_waits
  4. The innodb_lock_waits and x$innodb_lock_waits Views MySQL
    คิวรีที่รออยู่ (waiting_query), เซสชันที่ขวางอยู่ (blocking_pid) และเวลาที่รอ (wait_age)
  5. The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
    wait_event_type ของ pg_stat_activity: ถ้าเป็น Lock แปลว่ากำลังรอ heavyweight lock
  6. pg_locks (PostgreSQL Documentation) PostgreSQL
    ถ้า granted เป็น false แปลว่าโปรเซสนั้นกำลังรอให้ได้ล็อก
  7. Error Reporting and Logging (PostgreSQL Documentation) PostgreSQL
    log_lock_waits: บันทึก log เมื่อรอล็อกนานกว่า deadlock_timeout, ค่าเริ่มต้นปิด

สาเหตุที่ควรดูประกอบ

ชั้นเดียวกัน: L12 ฐานข้อมูล

สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (กดไม่ติด/โรลแบ็ค)

ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง