ลองสร้างฐานข้อมูลอนุกรมเวลาตั้งแต่พื้นฐาน
(nakabonne.dev)-
เขียนด้วย Go แต่แทบไม่ขึ้นกับภาษา
-
ข้อมูลอนุกรมเวลาเป็นคอลเลกชันของค่าหลายค่าที่มี timestamp กำกับ แต่ละรายการคือ data point
→ ปริมาณมาก และต้องมากจึงจะมีความหมาย หลายกรณีมีการเก็บข้อมูลระดับล้านครั้งต่อวินาที
→ Append-only, เรียงตามเวลา, ให้ความสำคัญกับข้อมูลล่าสุด
→ อ่านข้อมูลแบบก้อนตามหน่วยเวลาเฉพาะ
→ High Cardinality (ขนาดของเซ็ตใหญ่มาก)
→ ส่วนใหญ่ใช้งานโดยอ่านข้อมูลล่าสุด
-
สำหรับสะท้อนลักษณะที่เน้นการเขียนเป็นหลักของข้อมูลอนุกรมเวลา จึงพัฒนาไลบรารีเอนจินฐานข้อมูล TStorage ด้วยภาษา Go
-
โมเดลข้อมูล
→ โมเดลข้อมูลแบบเชิงเส้น
→ แบ่งพาร์ทิชัน data point ตามหน่วยเวลา
→ แต่ละพาร์ทิชันทำงานเหมือน DB แยกอิสระที่มีข้อมูลทั้งหมดภายในช่วงเวลานั้น
→ ปรับให้เฉพาะ head และพาร์ทิชันถัดไปเป็น memory partition ที่เก็บอยู่บน heap ได้
→ เพื่อป้องกันการสูญหายของข้อมูล จะเขียนลง WAL (Write Ahead Log) ก่อนเขียนจริง
→ ข้อมูลของพาร์ทิชันก่อนหน้านั้นจะถูกเก็บเป็นไฟล์เดี่ยวบนดิสก์ และพาร์ทิชันบนดิสก์เป็นแบบอ่านอย่างเดียว
- เมมโมรีพาร์ทิชัน
→ ลิสต์ของ data point ถูกแสดงเป็นอาร์เรย์บน heap (คล้ายกับ Slice ของ Go)
→ เนื่องจาก latency และการซิงโครไนซ์ จึงเกิด out-of-order บ่อย หากอยู่ในพาร์ทิชันเดียวกันสามารถจัดเรียงใหม่ตอนบันทึกผ่านการบัฟเฟอร์ได้ หากเป็นคนละพาร์ทิชันก็ทำได้โดยเพิ่มต่อท้ายพาร์ทิชันก่อนหน้าที่ไม่ใช่ head
→ เก็บข้อมูลชุดเดียวกับที่บันทึกลง WAL จริง เพื่อให้กู้คืนได้แม้เกิดข้อผิดพลาด
- ดิสก์พาร์ทิชัน
→ ต่อหนึ่งพาร์ทิชันมีหนึ่งไดเรกทอรี เก็บทั้ง metadata และข้อมูลจริงที่ถูกบีบอัด (Prometheus V3 Storage ฉบับย่อ)
→ รูปแบบข้อมูลแบบ Memory-Mapped (ให้เคอร์เนลแคชผ่าน mmap ได้)
→ metadata อยู่ในรูปแบบ JSON เพื่อสร้างดัชนี
- การเข้ารหัสข้อมูลที่แสดงเป็นทูเพิลของ timestamp และ value ใช้วิธีเข้ารหัสที่เสนอในงานวิจัย Gorilla ของ Facebook
→ เข้ารหัส timestamp และ value ด้วยเมธอดที่ต่างกัน
→ timestamp เป็นค่า unsigned 64-bit integer โดยใช้การเข้ารหัสแบบ Delta-of-delta
✓ Delta encoding: วิธีที่บันทึกเฉพาะค่าต่างระหว่างค่าก่อนหน้าและค่าปัจจุบัน
✓ Delta-of-Delta encoding: โดยทั่วไปข้อมูลเกิดขึ้นตามช่วงเวลาที่แน่นอน จึงบันทึกเฉพาะเดลตาของเดลตา
✓ เนื่องจากเป็นการเข้ารหัสแบบความยาวแปรผัน Delta-of-Delta จึงใช้พื้นที่น้อยที่สุด
→ value เป็นค่า signed 64-bit floating-point และใช้การเข้ารหัสแบบ XOR
✓ ค่าแรกเก็บตรง ๆ
✓ นำค่าถัดไปมา XOR ถ้าได้ 0 แปลว่าเท่ากับค่าก่อนหน้า จึงเก็บเพียงบิต 0 หนึ่งบิต
✓ ถ้าไม่ใช่ 0 จะคำนวณจากบิตอื่น ๆ (Meaningful Bit)
✓ คำนวณจำนวนศูนย์ด้านหน้า/ด้านท้าย ถ้าจำนวนศูนย์เท่ากันจะเก็บเฉพาะ 0 และ meaningful bits แต่ถ้าไม่เท่ากันจะเก็บจำนวน leading zero, จำนวนของ Meaningful Bit และตัวบิตนั้นเอง
ยังไม่มีความคิดเห็น