คู่มือเกมแลค › L12 ฐานข้อมูล
คำสั่ง Redis ที่ช้า Redis blocking commands (single-threaded)
ID สาเหตุ db-redis-block · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
Redis ประมวลผลคำสั่งทีละคำสั่ง คำสั่งที่ช้าเพียงคำสั่งเดียวจึงขวางทุกคำขอที่ตามมา
ทำไม ใช้ KEYS ค้นทั้งหมดระหว่างให้บริการ, อ่านหรือลบอันดับหรือลิสต์ที่มีสมาชิกหลายล้านตัวทั้งก้อน → ผลคือ คำขออื่นทั้งหมดต้องรอจนคำสั่งนั้นเสร็จ (หลายสิบ ms ถึงหลายวินาที) → บนหน้าจอ ฟีเจอร์ที่ใช้เซสชัน อันดับ และแคชหยุดแวบพร้อมกัน, ล็อกอินช้า
- อาการ
- ค้าง, อินพุตดีเลย์, เข้าเกมไม่ได้/โหลดไม่จบ
- ปัจจัย
- การหยุดชะงัก, ความหน่วง
- ใครเจอ
- ทั้งเซิร์ฟเวอร์, เฉพาะบางฟีเจอร์
- เกิดเมื่อไร
- สุ่มเป็นครั้งคราว, เป็นรอบสม่ำเสมอ
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
- งานฝั่งทีมพัฒนาเกม
- ใช้ SCAN แทน KEYS, แบ่งคีย์ใหญ่, ลบด้วย UNLINK (ลบเบื้องหลัง), กระจายเวลาหมดอายุที่กระจุกอยู่ในวินาทีเดียวกัน
- งานฝั่งทีมอินฟรา
- เฝ้าดูบันทึกคำสั่งช้า (SLOWLOG), บล็อกคำสั่งอันตรายอย่าง KEYS บนเซิร์ฟเวอร์ที่ให้บริการจริง, ตรวจคีย์ใหญ่เป็นประจำ, ปิด THP และกันหน่วยความจำไว้พอสำหรับ fork, ทำการบันทึก RDB และ AOF บน replica
- ตัวเลขที่ควรรู้
- คำสั่งทั่วไปใช้ไม่ถึง 1 ms ถ้าจัดการสมาชิกหลายล้านตัวในครั้งเดียว อาจใช้ตั้งแต่หลายร้อย ms ไปจนถึงหลายวินาที
- บนกราฟ
- พุ่งแบบสุ่มเป็นครั้งคราว · ดีเลย์การตอบของ Redis, จำนวนคำสั่งที่ช้า
- จุดที่ต้องดู
- ดูคำสั่งที่เกิน slowlog-log-slower-than ด้วย SLOWLOG GET และเปิด latency monitor (ค่าเริ่มต้นปิด) ด้วย CONFIG SET latency-monitor-threshold แล้วดูดีเลย์แยกตามอีเวนต์ เช่น fork และ expire-cycle ด้วย LATENCY LATEST และ LATENCY DOCTOR ตรวจเวลา fork และคีย์ใหญ่ด้วย latest_fork_usec ใน INFO และ redis-cli --bigkeys
- สัญญาณว่าใช่
- ช่วงที่หยุด SLOWLOG มีคำสั่ง KEYS หรือคำสั่งที่จัดการคีย์ใหญ่ทั้งก้อน หรือ LATENCY บันทึกอีเวนต์ fork หรือ expire-cycle ในช่วงเดียวกันนานตั้งแต่หลายสิบ ms ขึ้นไป
- สัญญาณว่าไม่ใช่
- SLOWLOG และ LATENCY ว่างแต่ช้าเฉพาะฝั่งเซิร์ฟเวอร์เกม: น่าจะเป็นเครือข่ายหรือการรอภายในเซิร์ฟเวอร์เกม (SLOWLOG วัดแค่เวลารันคำสั่ง ไม่รวมเวลารับส่งกับไคลเอนต์)
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
- รายละเอียดเพิ่มเติม
- ตอน fork โปรเซสเพื่อสร้างไฟล์บันทึก (RDB snapshot) หรือเขียน AOF ใหม่ ก็หยุดเช่นกัน บนเซิร์ฟเวอร์ปัจจุบันใช้ราว 10 ms ต่อหน่วยความจำ 1 GB ถ้า 30 GB ก็ประมาณ 300 ms ถ้าเปิด huge page (THP) ไว้ หลัง fork การเขียนแต่ละครั้งจะคัดลอก huge page ทั้งหน้า (copy-on-write) ทำให้ทั้งเวลาหยุดและการใช้หน่วยความจำเพิ่มขึ้นมาก จึงมักปิด THP และกันหน่วยความจำเหลือไว้มาก ๆ ตอนที่คีย์จำนวนมากหมดอายุในวินาทีเดียวกัน Redis ก็หยุดแวบเพราะต้องลบคีย์เหล่านั้น
แหล่งอ้างอิง
- Diagnosing latency issues Redis
เธรดเดียวประมวลผลคำขอตามลำดับ คำสั่งที่ช้าจึงขวางทุกคำขอที่ตามมา, ใช้ SCAN แทน KEYS, fork วัดจริงบนเครื่อง physical และ VM รุ่นใหม่ได้ราว 9–13 ms ต่อ 1 GB, THP ทำให้ดีเลย์และหน่วยความจำพุ่งจากการคัดลอกหลัง fork, คีย์จำนวนมากหมดอายุในวินาทีเดียวกันทำให้หยุด - KEYS Redis
ใช้บน production ด้วยความระมัดระวังอย่างยิ่ง อาจทำลายประสิทธิภาพบน DB ขนาดใหญ่ได้ (บนโน้ตบุ๊กระดับทั่วไป คีย์ 1,000,000 ตัวใช้ 40 ms) - UNLINK Redis
การลบแบบ asynchronous ที่ถอดคีย์ออกทันทีแล้วไปคืนหน่วยความจำในเธรดอื่น - SLOWLOG Redis
log คำสั่งช้าที่บันทึกคำสั่งที่เกิน slowlog-log-slower-than, เวลารันไม่รวม I/O รับส่งกับไคลเอนต์ - Redis latency monitoring Redis
latency-monitor-threshold ค่าเริ่มต้น 0 (ปิด), LATENCY LATEST และ LATENCY DOCTOR, บันทึกดีเลย์แยกตามอีเวนต์ เช่น fork และ expire-cycle - INFO Redis
latest_fork_usec: เวลาที่ fork ครั้งล่าสุดใช้ (ไมโครวินาที) - Redis CLI Redis
--bigkeys: ไล่ดู keyspace เพื่อหาคีย์ใหญ่
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: L12 ฐานข้อมูล
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (ค้าง)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง