คู่มือเกมแลค › L12 ฐานข้อมูล
ทรานแซกชันที่เปิดทิ้งไว้นาน Long-running transaction / MVCC purge lag
ID สาเหตุ db-long-tx · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
ถ้าทรานแซกชันหนึ่งเปิดทิ้งไว้นาน จะถือล็อกไว้ตลอด และ DB ล้างข้อมูลเวอร์ชันเก่า (purge) ไม่ได้ ทั้งระบบจึงค่อย ๆ ช้าลง
ทำไม เปิดทรานแซกชันไว้แล้วรอคำตอบจากเซิร์ฟเวอร์อื่น หรือรันคิวรีสรุปผลยาว ๆ บน DB หลักระหว่างให้บริการ → ผลคือ ล็อกที่ถือไว้ไม่ถูกปล่อย และข้อมูลเวอร์ชันเก่าที่ต้องล้างสะสมเรื่อย ๆ → บนหน้าจอ ฟีเจอร์ที่ใช้แถวนั้นไทม์เอาต์, การเซฟและการอ่านข้อมูลโดยรวมช้าลงตลอดหลายชั่วโมง
- อาการ
- อินพุตดีเลย์, กดไม่ติด/โรลแบ็ค
- ปัจจัย
- ความหน่วง, การหยุดชะงัก
- ใครเจอ
- เฉพาะบางฟีเจอร์, ทั้งเซิร์ฟเวอร์
- เกิดเมื่อไร
- ยิ่งเปิดไว้นานยิ่งเป็น, สุ่มเป็นครั้งคราว
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟรา DB (ทีมอินฟรา)
- งานฝั่งทีมพัฒนาเกม
- ไม่รอ network call หรืออินพุตจากผู้ใช้ภายในทรานแซกชัน, รันคิวรีสรุปผลบน replica
- งานฝั่งทีมอินฟรา
- ตั้ง alert และบังคับปิดทรานแซกชันที่เปิดนาน, จัด replica สำหรับงานสรุปผล, เฝ้าดูการเพิ่มของ undo log และ dead tuple
- บนกราฟ
- ค่อย ๆ สูงขึ้น · ความยาว undo log (History list length), จำนวน dead tuple
- จุดที่ต้องดู
- MySQL หาทรานแซกชันที่เก่าที่สุดจาก trx_started ใน INFORMATION_SCHEMA.INNODB_TRX และดู History list length (ปริมาณ undo log ที่ยังล้างไม่ได้) ในส่วน TRANSACTIONS ของ SHOW ENGINE INNODB STATUS ส่วน PostgreSQL ดู xact_start และเซสชันที่ state เป็น idle in transaction ใน pg_stat_activity และ n_dead_tup ใน pg_stat_user_tables
- สัญญาณว่าใช่
- มีทรานแซกชันที่เปิดมาไม่กี่นาทีถึงหลายชั่วโมง ระหว่างนั้น History list length หรือ n_dead_tup สูงขึ้นเรื่อย ๆ และลดลงเมื่อปิดทรานแซกชันนั้นแล้วการล้าง (purge, VACUUM) ได้ทำงาน
- สัญญาณว่าไม่ใช่
- ไม่มีทรานแซกชันเก่าแต่ช้าโดยรวม: น่าจะเป็น checkpoint (db-checkpoint) หรือดิสก์
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
- รายละเอียดเพิ่มเติม
- DB เก็บเวอร์ชันเก่าไว้เพื่อให้ฝั่งที่อ่านเห็นข้อมูลก่อนถูกแก้ (MVCC) และลบบันทึกนี้ได้ก็ต่อเมื่อทรานแซกชันที่เก่าที่สุดจบแล้ว ถ้าทรานแซกชันเดียวเปิดอยู่หลายชั่วโมง MySQL จะมี undo log สะสม ส่วน PostgreSQL จะมีแถวที่ตายแล้ว (dead tuple) ซึ่ง VACUUM ล้างไม่ได้สะสมอยู่ ส่วน SQL Server บางครั้ง transaction log ไม่ลดขนาดลงจนดิสก์เต็ม
แหล่งอ้างอิง
- InnoDB Multi-Versioning MySQL
ถ้ายังมีทรานแซกชันที่อาจต้องเห็นเวอร์ชันเก่า จะทิ้ง update undo log ไม่ได้ rollback segment จึงโตขึ้น, แนะนำให้ commit บ่อย ๆ แม้เป็นทรานแซกชันที่อ่านอย่างเดียว - Routine Vacuuming (PostgreSQL Documentation) PostgreSQL
เวอร์ชันเก่าของแถวลบไม่ได้ตราบที่ทรานแซกชันอื่นยังมองเห็นได้, ทรานแซกชันที่เปิดนานต้องจบหรือปิดเซสชัน - Client Connection Defaults (PostgreSQL Documentation) PostgreSQL
idle_in_transaction_session_timeout: ตัดเซสชันที่เปิดทรานแซกชันไว้แล้วอยู่เฉย ๆ เพื่อไม่ให้ถือล็อกไว้นาน - Troubleshoot a full transaction log (SQL Server Error 9002) Microsoft SQL Server
active transaction ที่รันนานขวางการล้าง transaction log - The INFORMATION_SCHEMA INNODB_TRX Table MySQL
TRX_STARTED: เวลาที่ทรานแซกชันเริ่ม - Purge Configuration MySQL
purge ล้างรายการ undo log ของทรานแซกชันที่ commit แล้ว (history list), ปริมาณที่กองรอแสดงเป็น History list length ในส่วน TRANSACTIONS ของ SHOW ENGINE INNODB STATUS - The Cumulative Statistics System (PostgreSQL Documentation) PostgreSQL
xact_start (เวลาที่ทรานแซกชันเริ่ม) และ state (idle in transaction) ใน pg_stat_activity, n_dead_tup (จำนวน dead tuple โดยประมาณ) ใน pg_stat_user_tables
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: L12 ฐานข้อมูล
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (อินพุตดีเลย์)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง