SQLite ล็อกไม่ไหลลื่น? Jellyfin แก้เกมด้วยกลยุทธ์ล็อกอัจฉริยะ
ลองจินตนาการว่าคุณกำลังใช้แอปที่เก็บข้อมูลด้วย SQLite ซึ่งเป็นฐานข้อมูลที่เบาและทรงพลัง แต่จู่ๆ แอปก็แครชโดยไม่มีเหตุผลชัดเจน ทั้งที่คุณแค่สั่งให้มันเขียนข้อมูลเพิ่ม… นี่คือปัญหาที่ Jellyfin เจอมาอย่างยาวนาน และตอนนี้พวกเขาได้แชร์วิธีแก้ไขที่น่าสนใจสำหรับนักพัฒนา EF Core ทุกคน
SQLite: ฐานข้อมูลที่ดีแต่มีข้อจำกัด SQLite เป็นฐานข้อมูลแบบไฟล์เดียวที่ทำงานในแอปโดยตรง ไม่ต้องพึ่งเซิร์ฟเวอร์ภายนอก แต่ข้อจำกัดคือมันไม่เหมาะกับการเขียนข้อมูลพร้อมกันหลายๆ ครั้ง เพราะมันล็อกไฟล์ไว้ขณะเขียน ทำให้เกิดปัญหา “database is locked” ได้ง่าย โดยเฉพาะในแอปที่มีการเขียนข้อมูลแบบขนาน
WAL (Write-Ahead Logging): ตัวช่วยแต่ไม่ใช่คำตอบ แม้ SQLite จะมีโหมด WAL ที่ช่วยให้เขียนข้อมูลแบบขนานได้บ้าง แต่ก็ยังมีสถานการณ์ที่ WAL ไม่สามารถป้องกันการล็อกได้ทั้งหมด โดยเฉพาะเมื่อมีธุรกรรม (transaction) ที่ยาวหรือซับซ้อน
Jellyfin เจอปัญหาเต็มๆ ก่อนเวอร์ชัน 10.11 Jellyfin มีบั๊กที่ทำให้เกิดการ overscheduling งานสแกนไลบรารี ส่งผลให้ SQLite ถูกถล่มด้วยคำสั่งเขียนหลายพันคำสั่งพร้อมกัน จนระบบ retry ก็เอาไม่อยู่ ทำให้แอปแครชบ่อยโดยไม่มีสาเหตุแน่ชัด
EF Core + Interceptor: ทางออกที่ Jellyfin เลือกใช้ เมื่อ Jellyfin ย้ายมาใช้ EF Core เต็มรูปแบบ พวกเขาใช้ “Interceptor” เพื่อควบคุมการเขียนข้อมูลแบบขนาน โดยมี 3 กลยุทธ์หลัก:
1️⃣ No-Lock: ไม่ทำอะไรเลย ใช้ในกรณีทั่วไปที่ไม่มีปัญหา
2️⃣ Optimistic Locking: ลองเขียน ถ้าไม่สำเร็จค่อย retry
3️⃣ Pessimistic Locking: ล็อกทุกครั้งก่อนเขียน เพื่อป้องกันปัญหาโดยเด็ดขาด
Polly: ตัวช่วยในการ retry Jellyfin ใช้ไลบรารี Polly เพื่อจัดการ retry อย่างชาญฉลาด โดยจะ retry เฉพาะคำสั่งที่ล้มเหลวจากการล็อกเท่านั้น
อนาคต: Smart Locking ทีม Jellyfin กำลังพิจารณาการผสมผสานระหว่าง Optimistic และ Pessimistic เพื่อให้ได้ทั้งความเร็วและความเสถียร
SQLite มีข้อจำกัดด้าน concurrency
ไม่สามารถเขียนข้อมูลหลายคำสั่งพร้อมกันได้ดี
WAL ช่วยได้บางส่วน
แต่ยังมีโอกาสเกิดการล็อกเมื่อมีธุรกรรมซับซ้อน
Jellyfin เจอปัญหาแครชจากการเขียนขนาน
เกิดจากบั๊ก overscheduling และธุรกรรมที่ไม่เหมาะสม
EF Core Interceptor คือทางออก
ใช้ควบคุมการเขียนข้อมูลแบบขนานอย่างมีประสิทธิภาพ
มี 3 กลยุทธ์การล็อก
No-Lock, Optimistic Locking, Pessimistic Locking
Polly ใช้สำหรับ retry อย่างชาญฉลาด
ลดโอกาสแครชจากการล็อกซ้ำซ้อน
Smart Locking อาจเป็นอนาคต
ผสมข้อดีของทั้งสองแนวทางเพื่อประสิทธิภาพสูงสุด
ธุรกรรมที่ยาวหรือไม่เหมาะสมอาจทำให้ระบบล่ม
SQLite ไม่สามารถจัดการกับคำสั่งเขียนจำนวนมากพร้อมกันได้ดี
การเขียนขนานโดยไม่มีการควบคุมเสี่ยงต่อการแครช
แอปอาจล้มเหลวทันทีหากไม่มีระบบ retry หรือ locking ที่ดี
WAL ไม่ใช่คำตอบสุดท้าย
ยังมีสถานการณ์ที่ WAL ไม่สามารถป้องกันการล็อกได้
https://jellyfin.org/posts/SQLite-locking/ 🧠 SQLite ล็อกไม่ไหลลื่น? Jellyfin แก้เกมด้วยกลยุทธ์ล็อกอัจฉริยะ
ลองจินตนาการว่าคุณกำลังใช้แอปที่เก็บข้อมูลด้วย SQLite ซึ่งเป็นฐานข้อมูลที่เบาและทรงพลัง แต่จู่ๆ แอปก็แครชโดยไม่มีเหตุผลชัดเจน ทั้งที่คุณแค่สั่งให้มันเขียนข้อมูลเพิ่ม… นี่คือปัญหาที่ Jellyfin เจอมาอย่างยาวนาน และตอนนี้พวกเขาได้แชร์วิธีแก้ไขที่น่าสนใจสำหรับนักพัฒนา EF Core ทุกคน
📂 SQLite: ฐานข้อมูลที่ดีแต่มีข้อจำกัด SQLite เป็นฐานข้อมูลแบบไฟล์เดียวที่ทำงานในแอปโดยตรง ไม่ต้องพึ่งเซิร์ฟเวอร์ภายนอก แต่ข้อจำกัดคือมันไม่เหมาะกับการเขียนข้อมูลพร้อมกันหลายๆ ครั้ง เพราะมันล็อกไฟล์ไว้ขณะเขียน ทำให้เกิดปัญหา “database is locked” ได้ง่าย โดยเฉพาะในแอปที่มีการเขียนข้อมูลแบบขนาน
📝 WAL (Write-Ahead Logging): ตัวช่วยแต่ไม่ใช่คำตอบ แม้ SQLite จะมีโหมด WAL ที่ช่วยให้เขียนข้อมูลแบบขนานได้บ้าง แต่ก็ยังมีสถานการณ์ที่ WAL ไม่สามารถป้องกันการล็อกได้ทั้งหมด โดยเฉพาะเมื่อมีธุรกรรม (transaction) ที่ยาวหรือซับซ้อน
💥 Jellyfin เจอปัญหาเต็มๆ ก่อนเวอร์ชัน 10.11 Jellyfin มีบั๊กที่ทำให้เกิดการ overscheduling งานสแกนไลบรารี ส่งผลให้ SQLite ถูกถล่มด้วยคำสั่งเขียนหลายพันคำสั่งพร้อมกัน จนระบบ retry ก็เอาไม่อยู่ ทำให้แอปแครชบ่อยโดยไม่มีสาเหตุแน่ชัด
🔧 EF Core + Interceptor: ทางออกที่ Jellyfin เลือกใช้ เมื่อ Jellyfin ย้ายมาใช้ EF Core เต็มรูปแบบ พวกเขาใช้ “Interceptor” เพื่อควบคุมการเขียนข้อมูลแบบขนาน โดยมี 3 กลยุทธ์หลัก:
1️⃣ No-Lock: ไม่ทำอะไรเลย ใช้ในกรณีทั่วไปที่ไม่มีปัญหา
2️⃣ Optimistic Locking: ลองเขียน ถ้าไม่สำเร็จค่อย retry
3️⃣ Pessimistic Locking: ล็อกทุกครั้งก่อนเขียน เพื่อป้องกันปัญหาโดยเด็ดขาด
🧠 Polly: ตัวช่วยในการ retry Jellyfin ใช้ไลบรารี Polly เพื่อจัดการ retry อย่างชาญฉลาด โดยจะ retry เฉพาะคำสั่งที่ล้มเหลวจากการล็อกเท่านั้น
🚀 อนาคต: Smart Locking ทีม Jellyfin กำลังพิจารณาการผสมผสานระหว่าง Optimistic และ Pessimistic เพื่อให้ได้ทั้งความเร็วและความเสถียร
✅ SQLite มีข้อจำกัดด้าน concurrency
➡️ ไม่สามารถเขียนข้อมูลหลายคำสั่งพร้อมกันได้ดี
✅ WAL ช่วยได้บางส่วน
➡️ แต่ยังมีโอกาสเกิดการล็อกเมื่อมีธุรกรรมซับซ้อน
✅ Jellyfin เจอปัญหาแครชจากการเขียนขนาน
➡️ เกิดจากบั๊ก overscheduling และธุรกรรมที่ไม่เหมาะสม
✅ EF Core Interceptor คือทางออก
➡️ ใช้ควบคุมการเขียนข้อมูลแบบขนานอย่างมีประสิทธิภาพ
✅ มี 3 กลยุทธ์การล็อก
➡️ No-Lock, Optimistic Locking, Pessimistic Locking
✅ Polly ใช้สำหรับ retry อย่างชาญฉลาด
➡️ ลดโอกาสแครชจากการล็อกซ้ำซ้อน
✅ Smart Locking อาจเป็นอนาคต
➡️ ผสมข้อดีของทั้งสองแนวทางเพื่อประสิทธิภาพสูงสุด
‼️ ธุรกรรมที่ยาวหรือไม่เหมาะสมอาจทำให้ระบบล่ม
⛔ SQLite ไม่สามารถจัดการกับคำสั่งเขียนจำนวนมากพร้อมกันได้ดี
‼️ การเขียนขนานโดยไม่มีการควบคุมเสี่ยงต่อการแครช
⛔ แอปอาจล้มเหลวทันทีหากไม่มีระบบ retry หรือ locking ที่ดี
‼️ WAL ไม่ใช่คำตอบสุดท้าย
⛔ ยังมีสถานการณ์ที่ WAL ไม่สามารถป้องกันการล็อกได้
https://jellyfin.org/posts/SQLite-locking/