คู่มือเกมแลค › L9 โปรเซสเกมฝั่งเซิร์ฟเวอร์
การแย่งล็อก Lock contention
ID สาเหตุ sp-lock · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
ถ้าหลายเธรดรอล็อกตัวเดียวเพื่อเขียนข้อมูลเดียวกัน ต่อให้เพิ่มเธรด ก็ทำงานได้ทีละตัวเท่านั้น
ทำไม หลายเธรดใช้ข้อมูลที่ใช้ร่วมกันพร้อมกัน เช่น ตลาดประมูลหรือคลังกิลด์ → ผลคือ เธรดอื่นต้องรอจนเธรดที่ถือล็อกทำงานเสร็จ → บนหน้าจอ ช้าเฉพาะบางฟีเจอร์ ถ้าหนัก ทิกทั้งหมดก็ช้าไปด้วย
- อาการ
- อินพุตดีเลย์, ค้าง
- ปัจจัย
- การหยุดชะงัก
- ใครเจอ
- เฉพาะบางฟีเจอร์, ทั้งเซิร์ฟเวอร์
- เกิดเมื่อไร
- ตอนคนแห่มารวมกัน
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม)
- งานฝั่งทีมพัฒนาเกม
- แบ่งล็อกให้ละเอียดขึ้น, ลดงานที่ทำในล็อก, ใช้โครงสร้างแบบส่งข้อความ (กำหนดเธรดเจ้าของให้ข้อมูลแต่ละชุด แล้วให้เธรดอื่นส่งคำขอเป็นข้อความเท่านั้น)
- ตัวเลขที่ควรรู้
- ถ้างานในล็อกคิดเป็น 20% ของงานทั้งหมด ต่อให้เพิ่มเธรดเท่าไร throughput ก็ได้สูงสุด 5 เท่าของตอนมีเธรดเดียว ถ้า 40% จะหยุดที่ 2.5 เท่า
- บนกราฟ
- สูงตามจำนวนคนและโหลด · เวลาประมวลผลคำขอ, CPU และ context switch แยกตามเธรด
- จุดที่ต้องดู
- voluntary context switch แยกตามเธรด (cswch/s คือจำนวนครั้งที่หยุดรอทรัพยากร) จาก pidstat -w -t 1, จุดที่เธรดออกจาก CPU ไปรอ (เวลารอแยกตาม call stack) จาก bcc offcputime -p สำหรับ .NET ดูจำนวนการแย่งล็อกใน dotnet-counters (.NET 9 ขึ้นไปคือ dotnet.monitor.lock_contentions, 8 ลงไปคือ Monitor Lock Contention Count)
- สัญญาณว่าใช่
- โหลดเพิ่มแต่อัตราการใช้ CPU ยังต่ำ ขณะที่เวลาประมวลผลเพิ่มขึ้น เวลารอส่วนใหญ่กระจุกอยู่ใน call stack ที่พยายามถือล็อก และจำนวนการแย่งล็อกสูงขึ้นตาม
- สัญญาณว่าไม่ใช่
- CPU เต็ม: เป็นปัญหาปริมาณการคำนวณ (ทิกเกินงบเวลา, พื้นที่ที่รันบนเธรดเดียวโหลดเกิน) ถ้ารอการเรียก DB หรือไฟล์ น่าจะเป็น synchronous call บนเธรดเกม
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
- รายละเอียดเพิ่มเติม
- เกิดในโครงสร้างที่หลายเธรดแก้ข้อมูลเกมร่วมกัน โครงสร้างที่ให้เธรดเดียวดูแลแต่ละพื้นที่หรือฟีเจอร์และสื่อสารกันด้วยข้อความเท่านั้นแทบไม่มีล็อก แต่ต้องระวังปัญหางานกระจุกที่เธรดเดียว (พื้นที่ที่รันบนเธรดเดียวโหลดเกิน) ถ้าเธรดเกมรอล็อกที่งานบันทึกข้อมูลซึ่งช้าถืออยู่ ทั้งทิกนั้นจะหยุดชะงัก
- กรณีจริง
- Roblox 2021: Roblox ล่ม 73 ชั่วโมง: การแย่งทรัพยากรในคลัสเตอร์ service discovery (Consul)
แหล่งอ้างอิง
- Amdahl's Law in the Multicore Era IEEE
เปเปอร์ IEEE Computer 2008 (ฉบับที่ผู้เขียนเผยแพร่เอง) ถ้าสัดส่วนที่แบ่งทำแบบขนานไม่ได้คือ 1−f ต่อให้เพิ่มคอร์เท่าไร ความเร็วที่เพิ่มขึ้นก็ไม่เกิน 1/(1−f) (กฎของ Amdahl) - Request scheduling Microsoft
grain (actor) ของ Orleans ใช้โมเดลรันแบบเธรดเดียวที่ประมวลผลคำขอทีละรายการจนจบ จึงไม่มีการแก้สถานะพร้อมกัน, ถ้า grain รอการตอบกลับของกันและกันอาจเกิดเดดล็อก - pidstat(1) — Linux manual page sysstat
cswch/s ของ -w คือจำนวน voluntary context switch ที่หยุดเพราะรอทรัพยากร, -t แสดงแยกตามเธรด - Demonstrations of offcputime, the Linux eBPF/bcc version IO Visor
รวมเวลาที่เธรดหยุดอยู่นอก CPU (off-CPU) แยกตาม call stack, -p ระบุโปรเซส - Well-known EventCounters in .NET Microsoft
Monitor Lock Contention Count (monitor-lock-contention-count): จำนวนครั้งที่เกิดการแย่งกันตอนพยายามถือ monitor lock - .NET runtime metrics .NET
dotnet.monitor.lock_contentions ตั้งแต่ .NET 9: จำนวนครั้งที่เกิดการแย่งกันตอนพยายามถือ monitor lock นับตั้งแต่โปรเซสเริ่ม
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: L9 โปรเซสเกมฝั่งเซิร์ฟเวอร์
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (อินพุตดีเลย์)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง