10 คะแนน โดย GN⁺ 2024-01-16 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

การเปิดใช้งาน/ปิดใช้งานโหมด Wal2

  • โหมด "Wal2" ของ SQLite มีความคล้ายกับโหมด "wal (Write-Ahead Logging)" อย่างมาก
  • หากต้องการเปลี่ยนฐานข้อมูลเป็นโหมด wal2 ให้ใช้คำสั่ง PRAGMA journal_mode = wal2;
  • ไม่สามารถเปลี่ยนจากโหมด "wal" ไปเป็นโหมด "wal2" ได้โดยตรง และต้องเปลี่ยนเป็นโหมด rollback ก่อน
  • หากต้องการเปลี่ยนฐานข้อมูลโหมด wal ให้เป็นโหมด wal2 ให้ใช้คำสั่ง PRAGMA journal_mode = delete; จากนั้นจึงใช้ PRAGMA journal_mode = wal2;
  • ฐานข้อมูลโหมด wal2 สามารถเข้าถึงได้เฉพาะจาก SQLite เวอร์ชันที่คอมไพล์จากบรাঞ্চนั้นเท่านั้น
  • หากพยายามใช้ SQLite เวอร์ชันอื่น จะเกิดข้อผิดพลาด SQLITE_NOTADB
  • หากต้องการเปลี่ยนฐานข้อมูลโหมด wal2 กลับเป็นโหมด rollback เพื่อให้ SQLite ทุกเวอร์ชันเข้าถึงได้ ให้ใช้คำสั่ง PRAGMA journal_mode = delete;

ข้อดีของโหมด Wal2

  • ในโหมด wal เดิม เมื่อ writer เขียนข้อมูลลงฐานข้อมูล จะไม่แก้ไขไฟล์ฐานข้อมูลโดยตรง แต่จะเพิ่มข้อมูลใหม่ลงในไฟล์ "-wal"
  • การอ่านข้อมูลจะอ่านจากทั้งไฟล์ฐานข้อมูลต้นฉบับและไฟล์ "-wal"
  • ในบางช่วงเวลา ข้อมูลจากไฟล์ "-wal" จะถูกคัดลอกกลับไปยังไฟล์ฐานข้อมูล ซึ่งเรียกว่า "checkpoint"
  • checkpoint อาจทำแบบระบุชัดเจนผ่าน PRAGMA wal_checkpoint หรือ sqlite3_wal_checkpoint_v2() หรือทำโดยอัตโนมัติด้วยการตั้งค่า PRAGMA wal_autocheckpoint (ค่าเริ่มต้น)
  • checkpointer จะไม่บล็อก writer และ writer ก็จะไม่บล็อก checkpointer
  • แต่หาก writer เขียนลงฐานข้อมูลระหว่าง checkpoint ข้อมูลใหม่จะถูกเพิ่มต่อที่ท้ายไฟล์ wal ทำให้ไฟล์ wal อาจโตขึ้นเรื่อยๆ
  • ในโหมด wal2 จะไม่มีปัญหาไฟล์ wal โตไม่สิ้นสุด แม้ checkpointer จะไม่มีโอกาสทำงานจนเสร็จโดยไม่ถูกรบกวน
  • ในโหมด wal2 จะใช้ไฟล์ wal สองไฟล์แทนหนึ่งไฟล์ ("-wal" และ "-wal2")
  • เมื่อมีการเขียนข้อมูล writer จะเริ่มเพิ่มข้อมูลใหม่ลงในไฟล์ wal แรก
  • เมื่อไฟล์ wal แรกมีขนาดใหญ่พอ writer จะเริ่มเพิ่มข้อมูลลงในไฟล์ wal ที่สอง
  • หลังจากนั้นไฟล์ wal แรกจะสามารถทำ checkpoint ได้ และเมื่อไฟล์ wal ที่สองมีขนาดใหญ่พอและไฟล์แรกถูก checkpoint แล้ว ก็จะสลับกลับไปใช้ไฟล์แรกอีกครั้ง

การเขียนโปรแกรมประยุกต์

  • จากมุมมองของผู้ใช้ ความแตกต่างหลักระหว่างโหมด wal และ wal2 เกี่ยวข้องกับ checkpoint
  • ในโหมด wal สามารถพยายามทำ checkpoint ได้ทุกเมื่อ แต่ในโหมด wal2 จะทำ checkpoint ได้ก็ต่อเมื่อ writer สลับไปยังไฟล์ wal "อีกฝั่ง" แล้วเท่านั้น
  • ในโหมด wal wal-hook (callback) จะถูกเรียกหลังจาก transaction commit โดยส่งจำนวนหน้าทั้งหมดในไฟล์ wal เป็นอาร์กิวเมนต์
  • ในโหมด wal2 wal-hook จะถูกเรียกโดยใช้อาร์กิวเมนต์เป็นจำนวนหน้าที่ยังไม่ถูก checkpoint รวมของ wal ทั้งสองไฟล์ หรือเป็น 0 หากไฟล์ wal "อีกฝั่ง" ว่างอยู่หรือถูก checkpoint ไปแล้ว
  • แนะนำให้ไคลเอนต์ใช้กลยุทธ์ checkpoint แบบเดียวกับโหมด wal สำหรับฐานข้อมูลโหมด wal2
  • wal-hook จะถูกเรียกหลังจาก transaction ถูก commit ลงดิสก์และปลดล็อกฐานข้อมูลแล้ว แต่ยังเกิดขึ้นภายในการเรียก sqlite3_step()
  • ในระบบ BEGIN CONCURRENT แทนที่จะรัน checkpoint ภายใน wal-hook อาจใช้เธรดที่เลื่อนงานนี้ออกไปหลังจาก application mutex ถูกปล่อยแล้ว

ความเห็นของ GN⁺

  • โหมด wal2 ของ SQLite มอบแนวทาง journaling แบบใหม่ที่ช่วยเพิ่ม concurrency และประสิทธิภาพของฐานข้อมูล
  • การแก้ปัญหาไฟล์ wal โตไม่สิ้นสุดมีความสำคัญต่อการปรับปรุงเสถียรภาพและประสิทธิภาพของระบบ
  • นักพัฒนาควรทบทวนกลยุทธ์ checkpoint ของฐานข้อมูลเมื่อเริ่มใช้โหมด wal2 และจำเป็นต้องออกแบบ logic checkpoint ที่เหมาะสมเพื่อให้ได้ concurrency ที่ดียิ่งขึ้น

1 ความคิดเห็น

 
GN⁺ 2024-01-16
ความคิดเห็นบน Hacker News
  • ในโหมด WAL2 จะใช้ไฟล์ WAL สองไฟล์แทนที่จะเป็นไฟล์เดียว ไฟล์จะถูกตั้งชื่อเป็น "<database>-wal" และ "<database>-wal2" เมื่อมีการเขียนข้อมูลลงฐานข้อมูล การเขียนจะเริ่มจากการเพิ่มข้อมูลใหม่ลงในไฟล์ WAL แรก เมื่อไฟล์ WAL แรกมีขนาดใหญ่พอ การเขียนจะสลับไปเพิ่มข้อมูลลงในไฟล์ WAL ที่สอง ณ จุดนี้ ไฟล์ WAL แรกสามารถทำ checkpoint ได้ (และหลังจากนั้นสามารถเขียนทับได้) และเมื่อไฟล์ WAL ที่สองมีขนาดใหญ่พอและไฟล์แรกถูก checkpoint แล้ว ก็จะสลับกลับไปใช้ไฟล์ WAL แรกอีกครั้ง กระบวนการนี้จะดำเนินต่อไปเรื่อย ๆ

    • วิธีนี้สมเหตุสมผลมากจนไม่เข้าใจว่าทำไมโหมด WAL ถึงไม่ได้ถูกสร้างแบบนี้มาตั้งแต่แรก อาจเป็นเพราะถูกมองว่าเป็นการปรับแต่งที่เร็วเกินไปก็ได้
    • หวังว่าโหมดนี้จะพร้อมใช้งานได้ทั่วไปในที่สุด
  • Bedrock

    • Bedrock เป็นบรานช์ที่น่าสนใจกว่า
    • รวมฟีเจอร์ WAL2 + CONCURRENT
    • เป็นบรานช์ที่ Expensify ใช้เพื่อสเกลไปถึง 4M QPS บน single node (เมื่อ 6 ปีก่อน)
  • มีการให้ลิงก์ไปยัง left-right primitive ซึ่งเป็นเทคนิคที่คล้ายกับโหมด WAL2

    • เทคนิคนี้เก่ากว่า implementation ที่ลิงก์ไว้ แต่ถูกค้นพบขึ้นใหม่อย่างเป็นอิสระ และถูกเขียนขึ้นโดยเฉพาะเพื่อรองรับฐานข้อมูล SQL ประสิทธิภาพสูงอีกตัวหนึ่งชื่อ Noria
  • ในโหมด WAL2 จะใช้ไฟล์ WAL สองไฟล์แทนที่จะเป็นไฟล์เดียว ไฟล์จะถูกตั้งชื่อเป็น "<database>-wal" และ "<database>-wal2"

    • สงสัยว่าจะมีคนจำนวนเท่าไรที่ลบไฟล์ wal ทิ้ง เพราะคิดว่าเมื่อเปลี่ยนไปใช้ wal2 แล้ว ไฟล์ wal คือไฟล์ที่เหลือค้างอยู่
  • Microsoft SQL Server ใช้สถาปัตยกรรมที่คล้ายกัน แต่แทนที่จะใช้ไฟล์ log แยกต่างหาก จะจัดสรร Virtual Log Files (VLF) ภายในไฟล์ log ทางกายภาพ (บนดิสก์) โดย VLF จะถูกจัดสรรจาก ring buffer และอาจมีได้เป็นพันไฟล์

  • ดูออกเลยว่าฟีเจอร์นี้ยังไม่ออกตัวจริง

  • ผมกังวลมาตลอดว่า WAL มีไว้เพื่อช่วยรักษาความถูกต้องสมบูรณ์ของข้อมูลและช่วยกู้คืนจากการ crash แต่ตัวไฟล์เองกลับถูกเขียนแบบเป็นชุด ๆ (และ commit ลงดิสก์อย่างเชื่อถือได้) ไม่ใช่หลังจากทุกการเปลี่ยนแปลงในฐานข้อมูล เพื่อแลกกับประสิทธิภาพ แบบนี้มันไม่ทำลายจุดประสงค์ของมันหรือ? พูดในภาพรวม ไม่ได้จำกัดเฉพาะฐานข้อมูลนี้ และผมหาคำตอบเรื่องนี้ไม่เจอ

  • สงสัยว่าสิ่งนี้จะส่งผลอย่างไรกับระบบ SQLite แบบกระจายตัวรุ่นใหม่อย่าง Litestream

  • งั้นโดยพื้นฐานแล้วมันคือ double buffering สำหรับฐานข้อมูลใช่ไหม? ฟังดูเข้าใจได้

  • โหมด WAL2 ถูกรวมอยู่ในการ benchmark ของงานวิจัย HC-tree backend แล้ว