คู่มือเกมแลค › L12 ฐานข้อมูล
คนแห่ล็อกอินและคิวรี N+1 Login storm, N+1 queries
ID สาเหตุ db-login-storm · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
ถ้าการโหลดตัวละครหนึ่งตัวต้องดึงข้อมูลแยกกันหลายสิบครั้ง ผู้เล่นหลายหมื่นคนที่ล็อกอินพร้อมกันจะกลายเป็นคิวรีหลายล้านคิวรี
ทำไม ตอนโหลดตัวละคร ดึงไอเทม สกิล และเควสต์แยกกันทีละอย่าง → ผลคือ หลังปิดปรับปรุงใหม่ ๆ คนล็อกอินพร้อมกันจนคิวรีพุ่ง → บนหน้าจอ ล็อกอินโหลดไม่จบ, การเซฟของคนที่กำลังเล่นอยู่ก็ล่าช้าไปด้วย
อาการ เข้าเกมไม่ได้/โหลดไม่จบ , อินพุตดีเลย์
ปัจจัย การหยุดชะงัก, ความหน่วง
ใครเจอ ทั้งเซิร์ฟเวอร์
เกิดเมื่อไร หลังล็อกอิน/หลังปิดปรับปรุง
ผู้รับผิดชอบ ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
งานฝั่งทีมพัฒนาเกม ดึงข้อมูลรวมทีเดียว, คิวล็อกอิน, แคช, ตรวจจำนวนคิวรีที่เกิดจาก lazy loading ของ ORM
งานฝั่งทีมอินฟรา จัดอันดับคิวรีที่ถูกเรียกบ่อยแล้วแชร์, มอนิเตอร์จำนวนคิวรีและจำนวน connection ช่วงล็อกอินหลังปิดปรับปรุง
บนกราฟ พุ่งทันทีหลังเปิดเซิร์ฟ/ปิดปรับปรุง · จำนวนคิวรีต่อวินาทีของ DB, จำนวนการล็อกอิน
จุดที่ต้องดู วางจำนวนการล็อกอินหลังปิดปรับปรุงซ้อนกับจำนวนคิวรีต่อวินาทีของ DB (MySQL คือค่าที่เพิ่มขึ้นของ Questions) แล้วคำนวณจำนวนคิวรีต่อการล็อกอินหนึ่งครั้ง คิวรีที่ถูกเรียกบ่อยที่สุดดึงได้จาก COUNT_STAR ใน events_statements_summary_by_digest ของ MySQL และ calls ใน pg_stat_statements ของ PostgreSQL สัญญาณว่าใช่ การล็อกอินหนึ่งครั้งใช้คิวรีหลายสิบคิวรี และคิวรีอันดับต้น ๆ เป็นคิวรีสั้น ๆ หน้าตาเดียวกันที่ดึงข้อมูลด้วย ID ตัวละครตัวเดียว ถ้าจำนวนคิวรีต่อการล็อกอินเพิ่มขึ้นหลังแพตช์ แพตช์นั้นคือจุดเริ่มต้น สัญญาณว่าไม่ใช่ จำนวนคิวรีต่อการล็อกอินน้อยแต่แต่ละคิวรีช้า: น่าจะเป็น cold cache (db-cold-cache) หรืออินเด็กซ์ (db-no-index) วิธีตรวจ ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
รายละเอียดเพิ่มเติม lazy loading ของ ORM (ไลบรารีที่สร้างคิวรี DB ให้) สร้างคิวรีแบบนี้โดยที่นักพัฒนาเองก็ไม่รู้ตัว บนเซิร์ฟเวอร์ dev มีตัวละครไม่กี่ตัวจึงไม่เห็นผล แล้วมาโผล่ครั้งแรกตอนคนล็อกอินพร้อมกันบนเซิร์ฟเวอร์ live
แหล่งอ้างอิง Efficient Querying .NET lazy loading ของ ORM ทำให้เกิดปัญหา N+1 ที่ส่งคิวรีเพิ่มอีกหนึ่งครั้งต่อทุกรายการ ทำให้ประสิทธิภาพตกมาก, แนะนำให้โหลดรวมทีเดียว (eager loading) pg_stat_statements — track statistics of SQL planning and execution PostgreSQL รวบรวมจำนวนครั้งที่รัน (calls) และเวลารันรวมของแต่ละคำสั่ง เพื่อจัดอันดับคิวรีที่ถูกเรียกบ่อย Performance Schema Statement Digests and Sampling MySQL events_statements_summary_by_digest จัดกลุ่มคิวรีหน้าตาเดียวกันแล้วสรุปจำนวนครั้งและเวลา Statement Summary Tables MySQL COUNT_STAR (จำนวนครั้งที่รัน) และ SUM_TIMER_WAIT (เวลารวม) ในตารางสรุป Server Status Variables MySQL Questions: จำนวนคำสั่งที่ไคลเอนต์ส่งมา
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: L12 ฐานข้อมูล
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (เข้าเกมไม่ได้/โหลดไม่จบ)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง