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

คู่มือเกมแลค › 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 ไม่ลดขนาดลงจนดิสก์เต็ม

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

  1. InnoDB Multi-Versioning MySQL
    ถ้ายังมีทรานแซกชันที่อาจต้องเห็นเวอร์ชันเก่า จะทิ้ง update undo log ไม่ได้ rollback segment จึงโตขึ้น, แนะนำให้ commit บ่อย ๆ แม้เป็นทรานแซกชันที่อ่านอย่างเดียว
  2. Routine Vacuuming (PostgreSQL Documentation) PostgreSQL
    เวอร์ชันเก่าของแถวลบไม่ได้ตราบที่ทรานแซกชันอื่นยังมองเห็นได้, ทรานแซกชันที่เปิดนานต้องจบหรือปิดเซสชัน
  3. Client Connection Defaults (PostgreSQL Documentation) PostgreSQL
    idle_in_transaction_session_timeout: ตัดเซสชันที่เปิดทรานแซกชันไว้แล้วอยู่เฉย ๆ เพื่อไม่ให้ถือล็อกไว้นาน
  4. Troubleshoot a full transaction log (SQL Server Error 9002) Microsoft SQL Server
    active transaction ที่รันนานขวางการล้าง transaction log
  5. The INFORMATION_SCHEMA INNODB_TRX Table MySQL
    TRX_STARTED: เวลาที่ทรานแซกชันเริ่ม
  6. Purge Configuration MySQL
    purge ล้างรายการ undo log ของทรานแซกชันที่ commit แล้ว (history list), ปริมาณที่กองรอแสดงเป็น History list length ในส่วน TRANSACTIONS ของ SHOW ENGINE INNODB STATUS
  7. 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 ฐานข้อมูล

สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (อินพุตดีเลย์)

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