• เขียนด้วย 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 และตัวบิตนั้นเอง

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น