- SQLite เร็วมาก สามารถรองรับการอ่านพร้อมกันได้ราว ~168,000 ครั้งและการเขียน ~8000 ครั้งอย่างต่อเนื่องบนเซิร์ฟเวอร์ทั่วไปเครื่องเดียวระดับ ~40€/m
- เนื่องจากเป็นไลบรารีแบบฝังตัวที่ออกแบบมาสำหรับแอปพลิเคชันฝั่งไคลเอนต์ เช่น ระบบฝังตัว โทรศัพท์ และแอปเดสก์ท็อป ฐานข้อมูล SQLite จึงต้องอยู่ร่วมกับแอปพลิเคชันเซิร์ฟเวอร์ และไม่สามารถเข้าถึงผ่านเครือข่ายได้
- แล้วจะใช้ SQLite อย่างไรในสถานการณ์ที่ต้องมีมากกว่าหนึ่งเครื่อง?
- โปรเจกต์ทำเล่นช่วงสุดสัปดาห์อาจได้รับความนิยมแบบถล่มทลายจนต้องขยายระบบอย่างรวดเร็ว
- หนึ่งในข้อกำหนดของ CTO อาจเป็นการต้องดีพลอยบริการที่มีความพร้อมใช้งานสูงไปยังอย่างน้อย 2 ดาต้าเซ็นเตอร์ที่ต่างกัน
- ในช่วงไม่กี่ปีที่ผ่านมา มีหลายโปรเจกต์ที่พยายามดัดแปลง SQLite ให้เป็นฐานข้อมูลฝั่งแบ็กเอนด์สำหรับแอปพลิเคชันแบ็กเอนด์
- บทความนี้พยายามหาคำตอบว่านี่คือการเปลี่ยนกระบวนทัศน์ที่ช่วยให้องค์กรส่งมอบประสบการณ์ผู้ใช้ที่ดีกว่าได้เร็วขึ้น หรือเป็นเพียงกระแสการตลาดที่บริษัทต่าง ๆ ผลักดันเพื่อขยาย "จุดขายเฉพาะตัว (Unique Selling Proposition)" ของตน
การใช้ SQLite เป็นฐานข้อมูลที่เอดจ์
- SQLite กำลังถูกโปรโมตไม่ใช่แค่ในฐานะฐานข้อมูลแบ็กเอนด์ธรรมดา แต่ในฐานะฐานข้อมูลที่เอดจ์
- ผู้เล่นที่เด่นที่สุดคือ Cloudflare D1, fly.io ที่ใช้ LiteFS และ Turso
- ผลิตภัณฑ์ต่อยอดจาก SQLite ส่วนใหญ่ทำงานในลักษณะคล้ายกัน
- มีฐานข้อมูลหลักที่รับการเขียนอยู่ที่ใดที่หนึ่ง แล้วค่อยทำ replication แบบ asynchronous ไปยังภูมิภาคอื่น
- การทำ replication มักเกิดขึ้นโดยการสตรีมล็อกของทุกทรานแซกชันที่รันบนฐานข้อมูล หรือสตรีม Write-Ahead Log ของ SQLite
- ในสถาปัตยกรรมแบบนี้ ตามทฤษฎีแล้วการอ่านสามารถให้ศูนย์ข้อมูลเอดจ์จัดการได้ แต่การเขียนยังคงต้องถูกส่งกลับไปยังตำแหน่งศูนย์กลาง
- ในทางปฏิบัติ ลูกค้าคงไม่อยากเจอสถานการณ์ที่สั่งซื้อสินค้าในแอปอีคอมเมิร์ซสำเร็จแล้ว ฐานข้อมูล SQLite หลักอนุมัติคำสั่งซื้อเรียบร้อย แต่รีพลิกาสำหรับการอ่านในภูมิภาคยังตามไม่ทันและยังไม่ได้รับข้อมูลอัปเดต จนแสดงข้อความว่าไม่พบรายการ
- ยินดีต้อนรับสู่ "โลกอันเจ็บปวดของ Eventual Consistency"
วิธีแก้และข้อจำกัดของ LiteFS
- LiteFS เสนอวิธีแก้แบบกึ่งแฮ็ก โดยให้แอปพลิเคชันตั้งค่า
__txidcookie เพื่อติดตามทรานแซกชันล่าสุดที่รีพลิกาในภูมิภาคมีอยู่ และถ้ามันล้าหลังเกินไปก็ส่งคำสั่งอ่านไปยังฐานข้อมูลหลัก - ตอนนี้แอปพลิเคชันจึงถูกผูกแน่นกับฐานข้อมูลและ reverse proxy
- LiteFS ไม่ได้พูดถึงข้อเท็จจริงที่ว่ามันรองรับการเขียนได้เพียงประมาณ 100 ครั้งต่อวินาที
ข้อเสียหลักของระบบ SQLite แบบกระจายส่วนใหญ่
- ระบบ SQLite แบบกระจายส่วนใหญ่ไม่รองรับ interactive transaction ที่มีการคำนวณบางอย่างระหว่างคำสั่ง query ต่าง ๆ ภายในทรานแซกชัน
- สามารถมี write transaction ที่ active ได้เพียงหนึ่งรายการในเวลาเดียวกัน ในฐานข้อมูล SQLite ปกติ นี่มักไม่ใช่ปัญหาเพราะการเขียนส่วนใหญ่ใช้เวลาไม่เกินหลายสิบไมโครวินาที
- แต่เมื่อเพิ่ม latency ของเครือข่ายระหว่างแอปพลิเคชันกับฐานข้อมูล SQLite ระบบจะเริ่มพัง ฐานข้อมูลจะถูกล็อกตลอดช่วงเวลา round trip ของทรานแซกชัน และสุดท้ายจะถูกจำกัดเหลือการเขียนเพียงไม่กี่ครั้งต่อวินาที
- Turso "แก้" ปัญหานี้ด้วย batch โดยสามารถรวมหลาย query เข้าเป็น batch แล้วรันเป็นทรานแซกชันเดียว ส่วน Cloudflare D1 "แก้" ปัญหาด้วย batch และ stored procedure
ถ้ามีวิธีที่ง่ายกว่านี้ล่ะ?
- สำหรับเว็บแอปพลิเคชัน มีวิธีที่เรียบง่ายและทรงพลังมากซึ่งทำให้ระบบเร็วทั่วโลกได้อยู่แล้ว นั่นคือ HTTP caching ด้วย header
Cache-ControlและETag - การใช้ HTTP caching ช่วยหลีกเลี่ยงการต้องใช้เทคนิคคล้ายฐานข้อมูลแบบ weak consistency ซึ่งอาจทำให้เว็บแอปพลิเคชันซับซ้อนเกินไปหรือเสี่ยงต่อ race condition
- ผู้เขียนบทความนี้ใช้เวลาอย่างมากในหนังสือเล่มใหม่ "Cloudflare for Speed and Security" เพื่ออธิบายกลยุทธ์การแคชหลากหลายแบบที่ไม่เพียงทำให้เว็บแอปเร็วขึ้น แต่ยังรองรับผู้ใช้พร้อมกันจำนวนมากได้ด้วยทรัพยากรน้อยที่สุด
ฐานข้อมูลในฐานะ abstraction
- Latency ไม่ใช่ปัญหาเดียวที่ distributed SQLite พยายามแก้ อีกปัญหาคือความซับซ้อนด้านการปฏิบัติการ
- การดูแลคลัสเตอร์ของเซิร์ฟเวอร์ที่เชื่อมต่อกันผ่านเครือข่ายนั้นยาก และมักนำไปสู่ downtime กับการสูญเสียรายได้ ยังไม่รวมถึงการดูแลฐานข้อมูลซึ่งต้องอาศัยการบริหารจัดการอย่างต่อเนื่องและวัฒนธรรมด้านความปลอดภัยที่ดีเพื่อหลีกเลี่ยงหายนะอย่างที่ GitLab เคยเจอในปี 2017
- ดังนั้นแนวคิดก็คือการ bundle ฐานข้อมูลไปกับแอปพลิเคชันและวางทุกอย่างไว้บนเซิร์ฟเวอร์เครื่องเดียว
- แนวทางนี้ดีเมื่อมีนักพัฒนาเพียงคนเดียว แต่ในองค์กรขนาดใหญ่ก็มักจะมีคนหรือทีมที่รับผิดชอบการดูแลเซิร์ฟเวอร์ฐานข้อมูลโดยเฉพาะ
- นี่จึงเป็นเหตุผลที่ฐานข้อมูลซึ่งเข้าถึงผ่าน socket แทนที่จะเป็นไลบรารีแบบฝังตัว จึงเป็น abstraction ที่ยอดเยี่ยม เพราะจริง ๆ แล้วมันไม่ใช่ abstraction ทางเทคนิค แต่เป็น abstraction ทางองค์กร ระหว่างพัฒนา มันอาจเป็นแค่คอนเทนเนอร์ง่าย ๆ ที่รันบนเครื่องนักพัฒนา แต่ใน production มันอาจเป็นอะไรก็ได้ตั้งแต่คอนเทนเนอร์ที่รันบนเซิร์ฟเวอร์เดียวกับแอปพลิเคชัน ไปจนถึงคลัสเตอร์แบบกระจายที่เข้าถึงผ่านเครือข่าย นักพัฒนาเพียงสลับค่าคอนฟิกตัวเดียวคือ
DATABASE_URLแล้วทีมปฏิบัติการจะจัดการที่เหลือทั้งหมด - ในทางกลับกัน ระบบไฟล์ Unix แบบดั้งเดิมเป็น abstraction ที่ไม่เหมาะกับการประมวลผลแบบกระจาย แน่นอนว่ามี NFS (Network File System) แต่เนื่องจากระบบไฟล์ Unix ถูกออกแบบมาสำหรับการเข้าถึงจากเครื่องเดียว ประสิทธิภาพจึงไม่ดีนัก ตรงกันข้าม โปรโตคอล S3 เป็น abstraction ที่ค่อนข้างดีสำหรับการจัดเก็บข้อมูลไร้โครงสร้างจำนวนมากอย่างมีประสิทธิภาพ ขยายขนาดได้ และเชื่อถือได้ นักพัฒนาเพียงใช้ S3-compatible SDK แล้วก็แทบไม่ต้องคิดอะไรต่อ โดยทีมปฏิบัติการหรือผู้ให้บริการคลาวด์จะดูแลทุกอย่างให้ ไม่ว่าจะเป็นประสิทธิภาพ ความทนทาน หรือความเสถียร
บทสรุป
- SQLite เป็นฐานข้อมูลที่น่าทึ่งจริง ๆ แต่สำหรับทีมส่วนใหญ่ ควรหลีกเลี่ยง SQLite และเลือก PostgreSQL แทนจะดีกว่า
- มีชั่วโมงวิศวกรรมจำนวนมหาศาลที่ถูกใช้ไปกับการทำให้ PostgreSQL กลายเป็นฐานข้อมูลแบ็กเอนด์ที่ยอดเยี่ยมที่สุด หากเลือก SQLite คุณก็แทบเลี่ยงไม่ได้ที่จะต้องประดิษฐ์สิ่งที่ PostgreSQL มีมานานแล้วขึ้นใหม่ในแบบที่เปราะบางและเต็มไปด้วยบั๊ก
- ในตอนนี้ กระแสที่พยายามทำให้ SQLite เป็นฐานข้อมูลแบ็กเอนด์ ดูเป็นเพียงรัฐประหารทางการตลาดของบริษัทที่ขายโครงสร้างพื้นฐาน edge computing ซึ่งตระหนักว่าการประมวลผลนั้นไร้ความหมายหากไม่มี data store คำแนะนำแบบไม่ได้ร้องขอสำหรับพวกเขาคือ แทนที่จะสร้าง CDN แล้วผลักภาระความซับซ้อนไปให้แอปพลิเคชัน ควรลงทุนกับ HTTP caching ซึ่งให้ผลลัพธ์ที่ดีกว่ามาก
- เพราะความซับซ้อนที่ถูกเหนี่ยวนำขึ้น แอปพลิเคชันแบ็กเอนด์ 99.9% จะไม่ได้ประโยชน์อะไรจากการย้ายไปอยู่ที่เอดจ์ และควรโฟกัสกับการวางกลยุทธ์การแคชที่ดีเพื่อมอบประสบการณ์ระดับยอดเยี่ยมทั่วโลกด้วย latency ต่ำกว่า 100ms มากกว่า
- และนี่คือจุดสิ้นสุดของการทดลองใช้ SQLite สำหรับแอปพลิเคชันฝั่งเซิร์ฟเวอร์ ชัยชนะเป็นของ PostgreSQL
-
"มือสมัครเล่นคุยเรื่องยุทธวิธี มืออาชีพคุยเรื่องลอจิสติกส์ (Amateurs discuss tactics. Professionals discuss logistics.)"
ความหมายคือ เพื่อความสำเร็จ สิ่งที่สำคัญกว่าการตัดสินใจเชิงยุทธวิธีในภาคสนาม คือระบบและกระบวนการสนับสนุนที่ทำให้การตัดสินใจเหล่านั้นเกิดขึ้นได้ หรือก็คือลอจิสติกส์และการบริหารจัดการ
ความเห็นของ GN⁺
- ตามที่ผู้เขียนโต้แย้ง การใช้ SQLite ในแอปพลิเคชันแบ็กเอนด์ส่วนใหญ่ดูจะเพิ่มแต่ความซับซ้อนโดยแทบไม่มีประโยชน์ที่จับต้องได้ การใช้ฐานข้อมูลที่ผ่านการพิสูจน์และสุกงอมแล้วอย่าง PostgreSQL น่าจะเป็นทางเลือกที่ดีกว่า
- การที่ผู้ให้บริการโครงสร้างพื้นฐาน edge computing ผลักดัน SQLite ดูเหมือนเป็นส่วนหนึ่งของกลยุทธ์การตลาดมากกว่าข้อได้เปรียบทางเทคนิค การที่พวกเขาลงทุนกับ HTTP caching และ CDN มากกว่าน่าจะเป็นประโยชน์ต่อผู้พัฒนาแอปพลิเคชันมากกว่า
- แอปพลิเคชันแบ็กเอนด์ส่วนใหญ่สามารถให้บริการที่เร็วและขยายขนาดได้เพียงพออยู่แล้วด้วยกลยุทธ์การแคชที่เหมาะสม หากไม่ได้มีความจำเป็นต้องใช้ edge computing จริง ๆ ก็ควรหลีกเลี่ยงความซับซ้อนที่เกินจำเป็น
- distributed SQLite อาจมีประโยชน์ในบาง use case เฉพาะทาง แต่ยังดูมีข้อจำกัดหากจะใช้เป็นโซลูชันอเนกประสงค์ การตอบโจทย์ทั้งความสะดวกในการพัฒนา ประสิทธิภาพ และความสอดคล้องของข้อมูลไปพร้อมกันนั้นไม่ง่าย
- ท้ายที่สุด สิ่งที่สำคัญที่สุดคือการเลือกเทคโนโลยีให้เหมาะกับความต้องการของแอปพลิเคชันและศักยภาพของทีม แทนที่จะไหลไปตามกระแส ควรวิเคราะห์ข้อดีข้อเสียอย่างรอบคอบและตัดสินใจอย่างระมัดระวัง
- ผู้เขียนเน้นย้ำว่า SQLite ยังมีข้อบกพร่องหลายด้านสำหรับการใช้งานเป็นฐานข้อมูลแบ็กเอนด์ แต่ก็ไม่ได้หมายความว่าต้องตัดทิ้งทั้งหมด เพราะอาจยังมี use case อื่นที่สามารถใช้ประโยชน์จากจุดแข็งของ SQLite ได้
3 ความคิดเห็น
แทนที่จะถามว่าอะไรดีที่สุดระหว่าง Postgres กับ sqlite
ลองคิดดีกว่าไหมว่าในสองตัวนี้ อะไรเหมาะกับสถานการณ์ของเรามากกว่า
เพราะสิ่งที่ดีที่สุดย่อมเปลี่ยนไปตามสถานการณ์
ความคิดเห็นจาก Hacker News