ที่เก็บข้อมูล SQLite แบบหน่วงเวลาเป็นศูนย์ใน Durable Object ทุกตัว
(simonwillison.net)- Durable Object ของ Cloudflare เปลี่ยนจากที่เก็บข้อมูลแบบคีย์/ค่าไปเป็นที่เก็บข้อมูลเชิงสัมพันธ์บน SQLite ทำให้แอปพลิเคชันลอจิกและข้อมูลทำงานอยู่บนโฮสต์จริงเดียวกัน
- การขยายระบบทำโดยแยก Durable Object ตาม หน่วยสถานะแบบตรรกะ เช่น เอกสาร ผู้ใช้ หรือชาร์ดของฐานข้อมูล แทนการขยายวัตถุเดียวให้ใหญ่ขึ้น โดยวัตถุเดี่ยวมีข้อจำกัดจากการทำงานบนเครื่องเดียวและเธรดเดียว
- ในระบบที่มีหน่วยสถานะชัดเจนอย่างการจองเที่ยวบิน สามารถมี Durable Object เฉพาะพร้อมฐานข้อมูล SQLite ของตัวเองสำหรับแต่ละเที่ยวบินได้ ทำให้สายการบินหนึ่งอาจมีฐานข้อมูลใหม่หลายพันรายการต่อวัน
- ความทนทานของข้อมูลประกอบด้วย การสตรีม WAL entry การจัดเก็บลง object storage และการทำสำเนาไปยังดาต้าเซ็นเตอร์ใกล้เคียง โดยทำเป็นแบตช์ทุก 16MB หรือทุก 10 วินาที และรองรับการกู้คืนแบบ point-in-time ย้อนหลังได้สูงสุด 30 วัน
- JavaScript API เลือกใช้รูปแบบ blocking สำหรับงาน persistence แบบเธรดเดียวที่รวดเร็ว และตำแหน่งของ Durable Object จะคงที่หลังสร้างเสร็จ แต่มีแผนรองรับการย้ายตำแหน่งแบบไดนามิกในอนาคต
สถาปัตยกรรม Durable Object ที่เปลี่ยนมาใช้ SQLite
- Durable Object ของ Cloudflare ได้รับการอัปเกรดจากที่เก็บข้อมูลแบบคีย์/ค่าไปเป็น ระบบเชิงสัมพันธ์บน SQLite
- แกนสำคัญคือการวางแอปพลิเคชันลอจิกไว้ ในที่เดียวกัน กับข้อมูลที่ลอจิกนั้นจัดการ
- Durable Object หนึ่งตัวประกอบด้วยโค้ดที่ทำงานบนโฮสต์จริงเดียวกันกับฐานข้อมูล SQLite ที่มันใช้งาน
- แนวทางนี้มุ่งให้การอ่านและเขียนเกิดขึ้นได้โดยไม่ต้องมี network round trip จึงช่วยลด latency ได้ง่าย
- การรองรับงานขนาดใหญ่ใช้วิธีสร้างวัตถุเพิ่ม แทนการเพิ่ม throughput ของวัตถุเดี่ยว
- วัตถุเดี่ยวหนึ่งตัวทำงานบน single thread ของ single machine จึงมีข้อจำกัดด้าน throughput โดยธรรมชาติ
- ถ้าให้วัตถุแยกกันรับผิดชอบ หน่วยสถานะแบบตรรกะ ที่ต่างกัน เช่น เอกสาร ผู้ใช้ หรือ database shard ก็จะขยายระบบได้ง่ายกว่า
- ในระบบจองเที่ยวบิน สามารถแมปแต่ละเที่ยวบินไปยัง Durable Object เฉพาะพร้อมฐานข้อมูล SQLite ของตัวเองได้
- ในโครงสร้างนี้ สายการบินหนึ่งอาจสร้างฐานข้อมูลใหม่หลายพันรายการต่อวัน
- Durable Object แต่ละตัวมีชื่อเฉพาะของตัวเอง และเครือข่ายของ Cloudflare จะ route คำขอไปยังตำแหน่งของวัตถุนั้นภายในเครือข่ายทั่วโลก
ความทนทานด้วย WAL streaming และการทำสำเนา
- ระบบที่ใช้ Durable Object ได้แรงบันดาลใจจาก Litestream โดยจะสตรีมลำดับของ WAL entry ของแต่ละวัตถุไปยัง object storage อย่างต่อเนื่อง
- ทำเป็นแบตช์ทุก 16MB หรือทุก 10 วินาที
- สามารถ replay ธุรกรรมที่บันทึกไว้เพื่อทำ point-in-time recovery ย้อนหลังได้สูงสุด 30 วัน
- เพื่อเสริมความทนทานภายในหน้าต่างเวลา 10 วินาที การเขียนข้อมูลจะถูกส่งต่อไปยังสำเนา 5 ชุดในดาต้าเซ็นเตอร์ใกล้เคียงที่แยกจากกันทันทีหลัง commit
- ต้องมี 3 ชุดยืนยันก่อนจึงจะอนุมัติการตอบกลับการเขียน
- ระบบพื้นฐานของ Durable Objects คือ Storage Relay Service และ Cloudflare ได้ใช้งาน D1 SQLite system ที่แยกต่างหากนี้มานานกว่าหนึ่งปีแล้ว
API และพฤติกรรมตำแหน่งของวัตถุ
- JavaScript API ใช้รูปแบบ blocking ไม่ใช่ async
- เป้าหมายของการออกแบบคือการให้การทำงาน persistence แบบ single thread ที่รวดเร็ว
- โค้ดตัวอย่างจงใจใช้รูปแบบ N+1 query โดยดึงรายการเอกสารก่อน แล้วค่อยดึงชื่อผู้เขียนของแต่ละเอกสารด้วย query แยก
- SQLite ถูกยกให้เป็นกรณีที่เหมาะกับการจัดการรูปแบบนี้
- ปัจจุบัน Durable Object จะไม่ย้ายตำแหน่งหลังจากถูกสร้างแล้ว
- โดยปกติจะถูก instantiate ในดาต้าเซ็นเตอร์ที่อยู่ใกล้กับตำแหน่งที่เกิดคำขอ
get()ครั้งแรก - หากต้องการสร้างในตำแหน่งอื่นแบบกำหนดเอง สามารถส่งพารามิเตอร์เสริม
locationHintให้กับget()ได้ - การ ย้ายตำแหน่งแบบไดนามิก ของ Durable Object ที่มีอยู่แล้วเป็นแผนในอนาคต
- โดยปกติจะถูก instantiate ในดาต้าเซ็นเตอร์ที่อยู่ใกล้กับตำแหน่งที่เกิดคำขอ
- where.durableobjects.live เป็นเว็บไซต์สำหรับติดตามว่า Durable Object ใหม่ถูกสร้างขึ้นที่ไหนในเครือข่ายของ Cloudflare
- ในตัวอย่างการเข้าชม เมื่อโหลดหน้าเว็บจาก Half Moon Bay พบว่า worker ใน San Jose ได้สร้าง Durable Object ใน San Jose
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
มีประเด็นน่าสนใจเพิ่มเติมอยู่หลายอย่าง: API สำหรับเขียนเป็นแบบ synchronous แต่มีการรอแบบ asynchronous ที่ซ่อนไว้ ดังนั้นถ้าการเขียนล้มเหลวตอนกำลังส่ง response ถัดไป runtime จะเปลี่ยน response นั้นให้เป็น HTTP failure
ด้วยเหตุนี้ runtime จึงสามารถ จัด batch อัตโนมัติ สำหรับการเขียนและสมมติในเชิง optimistic ว่าจะสำเร็จได้ โดยที่ผู้ใช้ไม่ต้องจัดการ error หรือการรออย่างชัดเจน
ไม่มี read transaction ซึ่งน่าจะมีประโยชน์สำหรับการได้ pointer ไปยัง snapshot ณ ช่วงเวลาหนึ่ง
แต่ละ instance ของ runtime ถูกจำกัดไว้ที่ RAM 128MB
WebSocket สามารถเข้าสู่สถานะ hibernate ได้ และจะไม่ถูกคิดค่าใช้จ่ายในช่วงที่หลับอยู่ จึงสามารถคง client ให้เชื่อมต่ออยู่ได้แม้ในระหว่างที่ DO หลับ
ยังมีฟีเจอร์คล้าย RPC อัตโนมัติที่ทำให้เรียก DO หรือ Worker อื่นเหมือนการเรียก JS ปกติได้ แต่ในความเป็นจริงอาจเป็นการเรียกไปยัง data center อื่น และ runtime จะจัดการ serialization กับ parsing ให้
Litestream ที่กล่าวถึงในบทความก็เสนอเทคนิคที่คล้ายกัน
ใน SQLite ทั่วไป read transaction มีประโยชน์เพราะหลาย process สามารถเข้าถึง database เดียวกันพร้อมกันได้
แต่ที่นี่มีเพียง process เดียวที่เข้าถึง database ได้ ดังนั้นถ้าทำการอ่านทั้งหมดภายใน synchronous function เดียว หรือ implement lock ระดับ process เอง ก็จะได้ผลลัพธ์แบบเดียวกัน
การที่รายการ WAL ถูก stream แบบ batch ไปยัง object storage ทุก 16MB หรือทุก 10 วินาที ดูเหมือนหมายความว่า การอ่านข้อมูลที่เขียนจากทั่วโลกได้อย่างน่าเชื่อถืออาจใช้เวลาสูงสุด 10 วินาที
ผมไม่ค่อยเข้าใจว่าสิ่งนี้จะมาแทน cluster database แบบแยกตามภูมิภาคที่ตอบสนองระดับมิลลิวินาทีข้ามทวีปได้อย่างไร
เข้าใจว่าใช้ stream แต่ปลายทางมีเพียง follower 5 ตัว และ Cloudflare มี data center หลายร้อยแห่ง
ถ้า SQLite instance ทั้งหมดไม่ได้เชื่อมต่ออยู่ตลอดเวลา ก็รับประกันการอ่านระดับวินาทีไม่ได้ในทางกายภาพ และแม้จะเชื่อมต่ออยู่ packet delay ก็อาจก่อปัญหาได้
ถ้าเขียนแล้วอ่านทันที จะเห็นผลทันที เพราะการเขียนจะอัปเดต สถานะใน memory ของ process ปัจจุบันไปพร้อมกันด้วย
ถ้า process อื่น เช่น DO หรือ Worker อื่น ต้องการเข้าถึงข้อมูล ก็ต้องผ่าน DO ที่ถือข้อมูลอยู่ จึงจะส่งคำขอ RPC หรือ HTTP และได้รับข้อมูลล่าสุด
hibernate จะเกิดหลังจากไม่มี activity ไปสักระยะ ดังนั้นกรณีที่การเขียนกลายเป็น unavailable ผิดจากที่คาด น่าจะมีเพียงสถานการณ์ที่ DO หรือ Worker crash ทันทีหลังเขียน
บทความบล็อกของ Cloudflare อธิบายส่วนนี้ละเอียดกว่า ดังนั้นจึงรักษาความเร็วของการเขียนไว้ได้พร้อมกับได้ durability
เครื่องนั้นจะมีมุมมองที่สอดคล้องเสมอต่อ database SQLite ของตัวเอง
สามารถสร้าง object ได้หลายพันล้านตัว แต่แต่ละ object มี database แยกกัน
ไม่มีวิธีอ่าน database นั้นโดยตรงจากเครื่องอื่นที่ไม่ใช่เครื่องที่ DO กำลังรันอยู่
DO แต่ละตัวมีเอกลักษณ์ระดับ global และ DO ของ ID หนึ่ง ๆ จะรันอยู่ที่ใดที่หนึ่งเพียงตัวเดียว โดยใช้ SQLite บน storage local ของ data center นั้น
ส่วนที่ยังไม่ค่อยเข้าใจเกี่ยวกับ Durable Objects คือ ตำแหน่งทางกายภาพ
สงสัยว่ามันอยู่ในรีเจียนที่โฮสต์ API call ซึ่งเป็นสาเหตุให้ถูกสร้างขึ้นครั้งแรกหรือไม่
ถ้าเป็นอย่างนั้น ก็สงสัยต่อว่ามีกลไกย้าย DO ไปยังตำแหน่งอื่นโดยอัตโนมัติไหม เมื่อพบว่ามันถูกสร้างในอเมริกาเหนือ แต่หลังจากนั้นทราฟฟิกอ่าน/เขียนทั้งหมดมาจากออสเตรเลีย เป็นต้น
locationHintได้ ออสเตรเลียใช้"oc"ได้: https://developers.cloudflare.com/durable-objects/reference/...ควรทราบด้วยว่า “การย้ายตำแหน่งแบบไดนามิกของ Durable Objects ที่มีอยู่แล้วเป็นแผนในอนาคต”
มีเพียงประมาณ 10~11% ของ Cloudflare PoP เท่านั้นที่โฮสต์ Durable Objects
คำขอที่เข้ามายัง PoP อื่นเพื่อสร้าง DO จะถูกส่งต่อไปยังหนึ่งใน PoP ใกล้เคียงที่โฮสต์สิ่งนี้
เท่าที่จำได้ Orleans(https://www.microsoft.com/en-us/research/wp-content/uploads/...) สามารถย้าย actor ระหว่างเครื่องได้ ซึ่งโมเดลนี้น่าจะเข้ากันได้ดีกับวิธีการย้าย DO ระหว่างตำแหน่ง
แต่ไม่มี API call สำหรับย้าย Durable Object
ต้องไม่มีการเชื่อมต่ออยู่ และจะถูกสร้างขึ้นใหม่ในศูนย์ข้อมูลที่ใกล้ที่สุดกับการเชื่อมต่อถัดไปหรือการเชื่อมต่อแรก
ตอนนั้นหน่วยความจำจะหายไป แต่ที่เก็บข้อมูลยังคงอยู่
ช่วงหลังมีฟีเจอร์ย่อยเกี่ยวกับ hibernation เพิ่มเข้ามา ดังนั้นคำอธิบายนี้อาจเก่าไปเล็กน้อย
สงสัยว่ามีคนอื่นอีกไหมที่รู้สึกว่ายากที่จะเข้าใจเทคโนโลยีคลาวด์ใหม่ ๆ แบบนี้
ทำเว็บมามากกว่า 15 ปี และใช้สแต็ก Laravel / Postgres / Redis มาตลอด แต่พออ่านบทความแบบนี้แล้วก็รู้สึกว่า มันไม่เข้ากับตัวเอง
แอปทำงานร่วมกันแบบเรียลไทม์ที่นึกออกทันทีคือ Google Docs/Sheets, Notion, Miro, Figma เป็นต้น
ทั้งหมดเป็นแอปทำงานร่วมกันระดับโลก และไม่แน่ใจว่าสแต็ก Laravel จะรองรับกรณีใช้งานแบบนี้ได้หรือไม่
Google คงต้องทำเองเกือบทั้งหมด และน่าจะเป็นผู้บุกเบิกการใช้ CRDT
แต่เมื่อแพตเทิร์นเริ่มชัดเจนและองค์ประกอบต่าง ๆ กลายเป็น SaaS การทำงานร่วมกันแบบเรียลไทม์ขนาดใหญ่ก็ไม่ใช่ปัญหาวิศวกรรมมหึมาอีกต่อไป และทำให้ผลิตภัณฑ์ที่น่าสนใจกว่านี้เป็นไปได้
ชอบการออกแบบ Durable Object มาก โดยเฉพาะตรงที่เข้าใจได้ง่ายว่าภายในทำงานอย่างไร
ต่างจากโซลูชันจำนวนมากที่ออกแบบมาสำหรับข้อมูลเรียลไทม์ Durable Objects มี ความเรียบง่าย แบบ Redis กับอาหารอิตาเลียน คือเห็นวัตถุดิบทั้งหมด
ถ้ามีเวลา ทรัพยากร และศูนย์ข้อมูลเพียงพอ โปรแกรมเมอร์ที่มีฝีมืออ่านเอกสาร DO แล้วน่าจะสร้างสิ่งที่คล้ายกันขึ้นมาใหม่ได้
จึงตัดสินใจเรื่อง trade-off ที่เกี่ยวข้องได้ง่าย
แต่ก็กังวลว่า DO เหมาะกับการสร้างประสบการณ์เรียลไทม์ที่เร็วและมีโอเวอร์เฮดต่ำ เช่น ฟีเจอร์ให้คนห้าคนแก้ไขเอกสารแบบเรียลไทม์ แต่จะทำให้การวิเคราะห์และการสร้างภาพรวมทำได้ยากมาก
เช่นคำถามว่ากลุ่มไหนแก้ไขเอกสารใดเมื่อสัปดาห์ที่แล้ว และถ้าใส่ข้อมูลไว้ใน SQLite ก็อาจยิ่งยากขึ้น
เพราะคงต้องหาวิธี query อินสแตนซ์ SQLite ขนาดเล็กจำนวนมหาศาล แล้วรวมผลลัพธ์เข้าด้วยกัน จึงสงสัยว่า DO มีอะไรสำหรับเรื่องนี้หรือไม่
สุดท้ายเหตุผลที่กลับไปหา Postgres อยู่เสมอก็คือเรื่องนี้ เพราะใช้ได้ทั้งกับฟังก์ชันหลักของแอป รวมถึงภาพรวมและ BI ต่าง ๆ
เป็นการออกแบบที่น่าสนใจมาก แต่ระบบฉลาด ๆ แบบนี้สำหรับผมมักอยู่ใน uncanny valley เสมอ
กรณีที่จำเป็นจริง ๆ มีแค่สองแบบเท่านั้น: ต้องขยายระบบที่มีโหลดสูงมากอย่างชาญฉลาด หรือทำโปรเจกต์ของเล่นเพื่อความสนุก
ถ้าเป็นโปรเจกต์ของเล่น จะใช้อะไรก็ได้
แต่ถ้าเป็นโปรดักชันหรือใช้ในงานจริง ก็ต้องการสิ่งที่ผ่านการพิสูจน์แล้ว
ถ้าคุณไม่รู้ว่าจำเป็นต้องใช้สิ่งนี้ ก็แปลว่าไม่จำเป็น และใช้ของน่าเบื่ออย่างฐานข้อมูล Postgres กับ VM ก็พอ
แต่ในทางกลับกัน ถ้าคุณรู้ว่าจำเป็นต้องใช้ ก็จะลำบากขึ้น เพราะมันยังใหม่และยังไม่สุกงอมพอ จึงมีโอกาสสูงที่จะเจอ edge case แปลก ๆ จำนวนมาก ซึ่งคุณคงไม่อยากดีบักหรือยอมรับมัน
สุดท้ายก็ไม่รู้ว่าระบบแบบนี้ทำมาเพื่อใคร
มันเฉพาะทางเกินไปจนยากที่จะมีผู้เล่นจริงจังจำนวนมากใช้งานและทำให้สุกงอมได้ง่าย และก็ซับซ้อนเกินไปพร้อมข้อแลกเปลี่ยนเยอะเกินไปสำหรับ 99.9% ของบริษัท
กลุ่มเป้าหมายที่ชัดเจนดูเหมือนจะมีแค่นักพัฒนาที่เห็นของแวววาวแล้วสร้างบริษัทขึ้นมา หรือแย่กว่านั้นคือเอาบริษัทของคนอื่นไปสร้างทับบนนั้น แล้วไม่นานก็เสียใจและย้ายไปใช้สิ่งที่น่าเบื่อกว่า
ถ้าอยากสร้างอะไรแบบ Figma หรือ Google Docs อีกตัวหนึ่ง โมเดลการเขียนโปรแกรมของ Durable Objects ก็สะดวกมาก
บทความนี้ลงรายละเอียดมากกว่า: https://digest.browsertech.com/archive/browsertech-digest-cl...
บทความเก่านี้ก็ค่อนข้างเกี่ยวข้อง: http://ithare.com/scaling-stateful-objects/
สำหรับคนที่อ่านบทความมัลติเพลเยอร์ของ Figma แล้วคิดว่า “นี่แหละประมาณสิ่งที่ฉันต้องการ” Durable Objects น่าจะเหมาะ: https://www.figma.com/blog/rust-in-production-at-figma/
มีแนวทางอื่นด้วย ก่อนหน้านี้เคยลองใช้ CRDT บน WebRTC แล้วรู้สึกเหมือนเป็นเทคโนโลยีแห่งอนาคตจริง ๆ
แต่มันซับซ้อนกว่าพื้นฐานที่เป็น WebSocket ที่อยู่สักที่ในคลาวด์กับอินสแตนซ์ของคลาสเดียวมาก
การวางข้อมูลกับพฤติกรรมไว้ ในตำแหน่งเดียวกัน ช่วยลดความซับซ้อนได้จริงในเชิงปริมาณ
เพราะตัดความกังวลเรื่อง latency และ bandwidth ออกไป จึงลดทั้งความกังวลด้านปฏิบัติการและด้านการพัฒนา ผลกระทบของปัญหา N+1 อันโด่งดังก็ลดลงมากด้วย
คุณอาจโต้แย้งได้ว่า Postgres ที่เชื่อมผ่านเครือข่ายดีกว่าด้วยเหตุผลอื่น และจริง ๆ ก็อาจถูก
แต่ SQLite นั้นขึ้นชื่อเรื่องความน่าเบื่อและคาดเดาได้ และมีจุดแข็งที่เป็นที่รู้กันชัดเจน
ดังนั้นมันจึงกำลังได้รับความนิยมมากขึ้นบนฝั่งเซิร์ฟเวอร์ด้วย
อย่างไรก็ตาม วิธีสร้างฐานข้อมูลเล็ก ๆ จำนวนมากตามที่ Durable Objects เสนอนั้นผมไม่ค่อยชอบ
มันทำให้นึกถึงฝันร้ายของ NoSQL และอาจทำลาย invariant สำคัญ ๆ ของฐานข้อมูลเชิงสัมพันธ์ได้
ผมมองว่า SQLite เหมาะกว่ามากเมื่อใช้เป็น ฐานข้อมูลแบบเดี่ยว เหมือนผลิตภัณฑ์ D1 ของ Cloudflare
Cloudflare ต้องการกรณีความสำเร็จจากลูกค้าที่ดี และมีโอกาสสูงที่วิศวกรเก่ง ๆ จะช่วยดูให้ว่าเรื่องนี้ทำงานอย่างไร ช่วยได้อย่างไร และจะจัดการบั๊กอย่างไร เพื่อแลกกับการได้กรณีความสำเร็จ
เมื่อพิสูจน์แล้วก็คงกลายเป็นความสัมพันธ์แบบบริการ แต่ช่วงแรกจะใกล้เคียงกับ พาร์ตเนอร์ชิป
มีบริการจำนวนมาก เช่น เครื่องมือภายใน ที่ไม่ต้องการการจูนประสิทธิภาพหรือการสังเกตภายในเชิงลึก
ในกรณีเหล่านี้ ผมคิดว่าเฟรมเวิร์ก serverless เหมาะ เพราะช่วยลดเวลาที่ใช้กับการ deploy ได้มาก
ถ้าเร็วก็ย่อมดี แต่แทบไม่ค่อยเป็นข้อกำหนดหลัก
โดยทั่วไปข้อกำหนดหลักคือสร้างได้เร็วและต้องดูแลรักษาน้อย
Cloudflare อาจมอบประสบการณ์นักพัฒนาที่ดีในจุดนี้ได้ แต่นั่นไม่ใช่จุดขายหลักของพวกเขา และก็มีบริการคู่แข่งอีกมากที่บอกว่าช่วยให้พัฒนาแบบนี้ได้เร็ว
ในทางกลับกัน หากต้องการความสามารถในการดีบักและการสังเกตภายในสูง ผมคิดว่าบริการแบบนี้ไม่ค่อยเหมาะ
สิ่งสำคัญคือจะได้ metric อะไรบ้าง มีข้อมูลพอไหมที่จะเข้าใจว่าทำไม Durable Objects บางตัวถึงช้า แก้ได้ไหม การ logging เป็นอย่างไร และค่าใช้จ่ายเท่าไร
บริการแบบนี้อาจดีสำหรับสตาร์ทอัพที่อยากสร้างระบบกระจายตัวที่ฉลาดตั้งแต่วันแรกเพื่อเลื่อนความกังวลเรื่องการสเกลออกไป
แต่ถ้าเป็นบริษัทระดับ scale-up ผมคิดว่าน่าจะอยากย้ายไปใช้สิ่งที่มองลึกลงไปได้มากกว่า และการเปลี่ยนผ่านนั้นคงยาก
อย่างที่คนอื่น ๆ พูดกัน กรณีใช้งานคือมัลติเพลเยอร์ เพราะถ้าอยากให้แอปรู้สึกดี ทุกคนต้องเห็นการเปลี่ยนแปลงให้เร็วที่สุด
มองให้กว้างขึ้น อุตสาหกรรม storage พยายามมานานที่จะสร้างสิ่งที่สอดคล้องกัน, latency ต่ำ และเหมาะกับผู้ใช้หลายคน
แม้ในเชิงฟิสิกส์ก็มักมีข้อแลกเปลี่ยนระหว่าง consistency กับ latency จึงเป็นเรื่องยากมาก
ดังนั้นจึงกำลังลองหลายโมเดล และการทดลองจำนวนมากก็เกิดขึ้นรอบ ๆ SQLite แต่ไม่ใช่ทั้งหมด มีข้อยกเว้นอย่าง Yugabyte หรือ Cockroach ด้วย
ผมยังคงทึ่งกับการออกแบบของ DO
เรามักมีปฏิกิริยาโดยสัญชาตญาณว่าวิธีนี้ต้องมีอะไรผิดแน่ ๆ แต่จริง ๆ แล้วผมคิดว่าผลิตภัณฑ์จริงจำนวนมากถูกจัดวางแบบนี้โดยนัยอยู่แล้ว
กล่าวคือสำหรับทุกหน่วยอะตอมิกที่ต้องการความสอดคล้องของทรานแซกชัน จะมีงานซับซ้อนจำนวนมากถูกทำในสเกลที่เล็กมาก
เมื่อมองย้อนกลับไป สิ่งที่เราสร้างที่ Framer สำหรับโปรเจกต์รองรับมัลติเพลเยอร์ ก็เป็นเวอร์ชันที่ประยุกต์มากขึ้นของสิ่งที่ DO ทำอยู่ตอนนี้
เนื้อหาการแก้ไขถูกทำซ้ำที่ 60 FPS และถูกนำไปใช้กับไคลเอนต์ทุกตัวตามลำดับที่ถูกต้อง และสุดท้ายเราก็สร้างสิ่งที่คล้าย WAL สำหรับการแก้ไขออบเจกต์ JSON ด้วย
ดังนั้นแม้อินสแตนซ์ของโปรเจกต์จะ crash ตัวสำรองก็สามารถรับช่วงต่อได้เหมือนไม่มีอะไรเกิดขึ้น
แม้ว่าจะยังไม่มีเวลาคอมมิต JSON patch ลงในออบเจกต์ข้อมูลโปรเจกต์ขนาดใหญ่ก็ตาม ก็ใช้วิธีประมวลผลทุก ๆ การอัปเดต N ครั้งหรือทุก ๆ M วินาทีตามที่อธิบายไว้ที่นี่
อาจเป็นคำถามโง่ ๆ ก็ได้ แต่สงสัยว่าในโครงสร้างแบบนี้จัดการ schema migration กันอย่างไร
เท่าที่เข้าใจ ดูเหมือนจะตั้งเป้าไปที่ฐานข้อมูลต่อ tenant หรือโครงสร้างที่แตกย่อยกว่านั้นอีก
เลยสงสัยว่ามีวิธีจัดการ schema migration อย่างมีสติหรือไม่ หรือคาดหวังว่าฐานข้อมูลลักษณะนี้จะมีอายุสั้นกว่า จึงต้องรองรับ DB/DO หลายเวอร์ชันไปจนกว่าจะถูกลบ
ในหัวคิดว่าถ้าทำบริการบุ๊กมาร์กที่มี DO ต่อผู้ใช้ก็น่าจะสนุกดี
แต่ทันทีที่อยากเพิ่มฟิลด์ใหม่ลงในตารางเดิม ก็จะเจอปัญหาค่อนข้างยุ่งยากที่ต้องนำการเปลี่ยนแปลงนั้นไปใช้กับ DO แต่ละตัว
บางทีตัวอย่างนั้นอาจเป็นข้อมูลที่อยู่ยาวเกินไป และการออกแบบนี้อาจเหมาะกับการใช้งานที่ชั่วคราวกว่านั้น
ถ้ามีใครเคยทำจริง อยากรู้ว่าจัดการกันอย่างไร
มีเวอร์ชันสำหรับ SQLite ที่เขียนด้วย Python อยู่ แต่ไม่แน่ใจว่าจะรันบน Durable Objects ได้ไหม ผ่าน WASM กับ PyOdide อาจเป็นไปได้
ไม่อย่างนั้นก็ต้องพอร์ตเป็น JavaScript
https://github.com/simonw/sqlite-migrate
ช่วงนี้ดูเหมือน Cloudflare กำลังผลักดันให้นักพัฒนา ใช้ DO ทุกที่ มากกว่า Worker
การเชื่อมต่อ WebSocket ของ Worker ก็ timeout หลังประมาณ 30 วินาที และวิธีที่แนะนำคือใช้ DO
เดโมแชทเดิมก็ใช้ DO กับ WebSocket มาตั้งแต่ปี 2020: https://github.com/cloudflare/workers-chat-demo
นี่หมายความว่า SQLite สำหรับ DO อาจสูญเสียข้อมูลได้สูงสุด 10 วินาที ในสถานการณ์ที่ DO ล้มเหลวหรือเปล่า?
ตรงนี้ดูเหมือน Simon น่าจะตั้งใจพูดว่า within ไม่ใช่ “beyond”