แนะนำ TimeSeries Data Abstraction Layer ของ Netflix
(netflixtechblog.com)- เมื่อ Netflix ขยายไปยังหลากหลายโดเมน เช่น VoD และ Gaming ความสามารถในการจัดเก็บและประมวลผลข้อมูลตามเวลาในปริมาณมหาศาลระดับเพตะไบต์ด้วยค่าหน่วงระดับมิลลิวินาทีจึงกลายเป็นสิ่งสำคัญ
- Netflix ได้พัฒนา TimeSeries abstraction บนพื้นฐานของ Key-Value abstraction และแพลตฟอร์ม Data Gateway เพื่อมอบโซลูชันที่สามารถจัดเก็บและคิวรีข้อมูลเหตุการณ์ตามเวลาได้อย่างมีประสิทธิภาพในหลากหลายกรณีการใช้งาน
ความท้าทาย
- ที่ Netflix มีการสร้างและใช้งานข้อมูลตามเวลาอย่างต่อเนื่องจากการโต้ตอบของผู้ใช้ การแสดงผลแอสเซ็ต และกิจกรรมของเครือข่ายไมโครเซอร์วิสที่ซับซ้อน
- การจัดการข้อมูลเหล่านี้อย่างมีประสิทธิภาพมีความสำคัญต่อการรับประกันประสบการณ์ผู้ใช้และความน่าเชื่อถือของระบบ
- ความท้าทายหลัก:
- ปริมาณงานสูง: ต้องรองรับการเขียนได้สูงสุด 10 ล้านรายการต่อวินาที พร้อมรักษาความพร้อมใช้งานในระดับสูง
- คิวรีอย่างมีประสิทธิภาพบนชุดข้อมูลขนาดใหญ่: ต้องจัดเก็บข้อมูลระดับเพตะไบต์ พร้อมคืนผลการอ่านด้วย primary key ในระดับมิลลิวินาทีต่ำ และรองรับการค้นหาและการรวมผลผ่านคุณสมบัติรองหลายแบบ
- การอ่านและเขียนแบบทั่วโลก: รองรับการอ่านและเขียนจากที่ใดก็ได้ทั่วโลก พร้อมมีโมเดลความสอดคล้องที่ปรับได้
- การกำหนดค่าที่ปรับได้: รองรับความสามารถในการแบ่งชุดข้อมูลบน data store แบบผู้เช่าเดี่ยวหรือหลายผู้เช่า
- การจัดการ burst traffic: ต้องรับมือกับทราฟฟิกที่พุ่งสูงขึ้นจากการเปิดตัวคอนเทนต์ใหม่หรือการกู้คืนจากเหตุขัดข้องระดับภูมิภาค
- ความคุ้มค่าด้านต้นทุน: ต้องลดต้นทุนโครงสร้างพื้นฐานให้ต่ำที่สุด พร้อมเพิ่มประสิทธิภาพการเก็บรักษาระยะยาว
TimeSeries abstraction
- การแบ่งข้อมูล: ใช้กลยุทธ์การแบ่งตามเวลาเฉพาะตัวและแนวทาง event bucket เพื่อจัดการเวิร์กโหลดแบบ burst ได้อย่างมีประสิทธิภาพและทำให้คิวรีง่ายขึ้น
- สตอเรจที่ยืดหยุ่น: ออกแบบให้เชื่อมต่อกับสตอเรจแบ็กเอนด์ได้หลากหลาย เช่น Apache Cassandra และ Elasticsearch
- ความสามารถในการกำหนดค่า: มีตัวเลือกที่ปรับแต่งได้หลากหลายสำหรับแต่ละ dataset เพื่อให้ยืดหยุ่นต่อกรณีการใช้งานที่แตกต่างกัน
- การขยายระบบ: รองรับทั้งการขยายแนวนอนและแนวตั้ง เพื่อรองรับ throughput และปริมาณข้อมูลที่เพิ่มขึ้นตามการเติบโตของฐานผู้ใช้และบริการของ Netflix
- โครงสร้างพื้นฐานแบบ shard: ใช้ Data Gateway Platform เพื่อปรับใช้โครงสร้างพื้นฐานแบบผู้เช่าเดี่ยวและ/หรือหลายผู้เช่า พร้อมการแยกการเข้าถึงและทราฟฟิกตามต้องการ
โมเดลข้อมูล
- ใช้โมเดลข้อมูลเหตุการณ์เฉพาะตัวที่ห่อหุ้มข้อมูลเหตุการณ์ไว้เพื่อให้คิวรีได้อย่างมีประสิทธิภาพ
- Event item: event item คือคู่คีย์-ค่าที่ผู้ใช้ใช้เก็บข้อมูลของเหตุการณ์หนึ่ง ๆ ตัวอย่าง: {"device_type": "ios"}
- Event: event คือคอลเลกชันแบบมีโครงสร้างที่ประกอบด้วย event item หนึ่งรายการขึ้นไป โดย event จะเกิดขึ้น ณ เวลาหนึ่ง และระบุด้วย timestamp ที่สร้างจากไคลเอนต์และตัวระบุเหตุการณ์ (เช่น UUID) การรวมกันของ event_time และ event_id จะเป็นส่วนหนึ่งของ idempotency key ที่ไม่ซ้ำกันของ event ทำให้ผู้ใช้สามารถ retry request ได้อย่างปลอดภัย
- TimeSeries ID: time_series_id คือชุดของเหตุการณ์ตั้งแต่หนึ่งรายการขึ้นไปที่เกิดขึ้นภายในช่วงการเก็บรักษาของ dataset เช่น device_id อาจเก็บเหตุการณ์ทั้งหมดที่เกิดขึ้นบนอุปกรณ์หนึ่งเครื่องในช่วงเวลาการเก็บรักษา ทุก event เป็น immutable และบริการ TimeSeries จะทำเพียง append event เข้าไปใน time series ID ที่กำหนด
- Namespace: namespace คือชุดของ time series ID และข้อมูล event ซึ่งแทน dataset ของ TimeSeries ทั้งหมด ผู้ใช้สามารถสร้างได้ตั้งแต่หนึ่ง namespace ขึ้นไปสำหรับแต่ละ use case และ abstraction นี้จะใช้ตัวเลือกการปรับแต่งต่าง ๆ ในระดับ namespace
API
- WriteEventRecordsSync: endpoint นี้เขียน batch ของ event และส่งการยืนยันความคงทนกลับไปยังไคลเอนต์ ใช้เมื่อผู้ใช้ต้องการการรับประกันด้าน durability
- WriteEventRecords: นี่คือเวอร์ชัน fire-and-forget ของ endpoint ข้างต้น โดยจะนำ batch ของ event เข้า queue โดยไม่มีการยืนยันความคงทน ใช้ในกรณีอย่าง logging หรือ tracing ที่ผู้ใช้ให้ความสำคัญกับ throughput มากกว่าและยอมรับการสูญหายของข้อมูลได้เล็กน้อย
- ReadEventRecords: เมื่อระบุ namespace, timeSeriesId, timeInterval และ eventFilters แบบเลือกได้ endpoint นี้จะคืน event ที่ตรงกันทั้งหมดโดยเรียงตาม event_time แบบลดหลั่น พร้อมค่าหน่วงต่ำระดับมิลลิวินาที
- SearchEventRecords: เมื่อให้เกณฑ์การค้นหาและช่วงเวลา endpoint นี้จะคืน event ที่ตรงกันทั้งหมด กรณีใช้งานลักษณะนี้เหมาะกับการอ่านแบบ eventually consistent
- AggregateEventRecords: เมื่อให้เกณฑ์การค้นหาและโหมดการรวมผล (เช่น DistinctAggregation) endpoint นี้จะทำการรวมผลที่กำหนดภายในช่วงเวลาที่ระบุ คล้ายกับ Search endpoint ผู้ใช้ต้องยอมรับ eventual consistency และอาจมีค่าหน่วงสูงกว่าในระดับวินาที
ชั้นสตอเรจ
- ชั้นสตอเรจของ TimeSeries ประกอบด้วย data store หลักและ data store สำหรับดัชนีที่เป็นทางเลือก
- Apache Cassandra เป็นตัวเลือกหลักสำหรับ data store ที่รับประกัน durability ในสถานการณ์ที่มี throughput สูง
- Elasticsearch เป็นตัวเลือกหลักสำหรับ data store ด้าน indexing
data store หลัก
- ใช้ Apache Cassandra เพื่อรองรับกรณีการใช้งานของ TimeSeries
- จัดการข้อมูลด้วย Temporal Partitioning ที่แบ่งข้อมูลออกเป็นชิ้นตามช่วงเวลา
- time slice: แมปกับตาราง Cassandra ที่สอดคล้องกับช่วงการเก็บรักษา
- time bucket: แบ่งข้อมูลซ้ำภายใน time slice เพื่อเพิ่มประสิทธิภาพของคิวรีตามช่วงเวลาเฉพาะ
- event bucket: แบ่งซ้ำ time bucket เพื่อรองรับการเขียนจำนวนมากใน time series ภายในช่วงเวลาสั้น ๆ
- ตารางข้อมูลใช้เก็บข้อมูล event จริง ส่วนตาราง metadata ใช้เก็บข้อมูลการตั้งค่า time slice แยกตาม namespace
data store สำหรับดัชนี
- ข้อมูลจะถูกทำดัชนีลงใน Elasticsearch เพื่อรองรับรูปแบบการเข้าถึงรองผ่านคุณสมบัติที่ไม่ใช่ primary key
- ผู้ใช้สามารถกำหนดรายการคุณสมบัติสำหรับการค้นหาและการรวมผลแยกตาม namespace ได้
Control plane
- data plane รับผิดชอบงานอ่าน/เขียน ส่วน control plane รับผิดชอบการกำหนดค่าทุกด้านของพฤติกรรม namespace
- data plane สื่อสารกับ TimeSeries control stack ซึ่งโต้ตอบกับ Data Gateway control plane
- การตั้งค่า namespace ช่วยให้ปรับแต่งสิ่งต่าง ๆ ได้อย่างยืดหยุ่น เช่น การแบ่งตามเวลา การบัฟเฟอร์ ความสอดคล้อง และการเก็บรักษา
การตั้งค่า namespace
- สามารถปรับแต่งหลายอย่างในระดับ namespace ผ่าน configuration snippet ที่แสดงให้เห็นถึงความยืดหยุ่นของบริการ
Infrastructure provisioning
- ระบบจะหาการตั้งค่าที่เหมาะสมที่สุดผ่านเวิร์กโฟลว์ provisioning แบบอัตโนมัติ โดยพิจารณาจากพารามิเตอร์ที่หลากหลาย
- หลังจาก provisioning โครงสร้างพื้นฐานเริ่มต้นแล้ว ระบบจะขยายต่อไปตามเวิร์กโหลดของผู้ใช้
การขยายระบบ
- เนื่องจากการคาดการณ์การใช้งานในช่วง provisioning เริ่มต้นมีข้อจำกัด จึงจำเป็นต้องมีการปรับหลังจากใช้งานจริง
- การขยายแนวนอน: อินสแตนซ์เซิร์ฟเวอร์ TimeSeries สามารถขยายขึ้นและลดลงโดยอัตโนมัติตามความต้องการทราฟฟิก
- การขยายแนวตั้ง: สามารถขยายอินสแตนซ์เซิร์ฟเวอร์ TimeSeries หรืออินสแตนซ์สตอเรจในแนวตั้ง เพื่อให้ได้ CPU, RAM และ/หรือความจุสตอเรจที่เชื่อมต่อมากขึ้น
- การขยายดิสก์: สามารถเชื่อมต่อ EBS เพื่อเก็บข้อมูลได้ และเมื่อพื้นที่ดิสก์ถึงเกณฑ์ที่กำหนด ระบบจะขยาย EBS volume
- ปรับ dataset ที่ถูกแบ่งมากเกินไปหรือน้อยเกินไปผ่านการ repartition ข้อมูล
หลักการออกแบบ
- Event idempotency: สร้าง idempotency ไว้ในทุก mutation endpoint เพื่อให้ผู้ใช้ retry request ได้อย่างปลอดภัย
- SLO-based hedging: กำหนดเป้าหมาย Service Level Objective (SLO) สำหรับ endpoint หลายประเภทเพื่อรับประกันประสิทธิภาพ
- Partial return: หากไคลเอนต์ไวต่อค่าหน่วง ก็สามารถรับชุดผลลัพธ์บางส่วนได้
- Adaptive pagination: หากชั้นบริการพิจารณาว่า dataset ของ time series มีความหนาแน่น ก็จะปรับ fanout factor แบบไดนามิก
- หน้าต่างการเขียนที่จำกัด: ทำให้ข้อมูลกลายเป็น immutable ให้เร็วที่สุดเท่าที่จะทำได้ เพื่อให้สามารถใช้การเพิ่มประสิทธิภาพต่าง ๆ ได้
- การบัฟเฟอร์การเขียน: เพื่อรองรับเวิร์กโหลดแบบ burst ระบบจะรวม event เข้าด้วยกันในช่วงเวลาสั้น ๆ เพื่อกระจายโหลดให้สม่ำเสมอ
- การบีบอัดแบบไดนามิก: เมื่อข้อมูลกลายเป็น immutable แล้ว จะใช้กลยุทธ์การบีบอัดเพื่อเพิ่มประสิทธิภาพการอ่าน
ประสิทธิภาพจริง
- บริการนี้สามารถบันทึกข้อมูลได้ด้วยค่าหน่วงต่ำระดับมิลลิวินาที พร้อมรักษาค่าหน่วงของ point read ให้คงที่
การใช้งาน Time Series ภายใน Netflix
TimeSeries abstraction มีบทบาทสำคัญในบริการหลักของ Netflix ตัวอย่าง use case ที่มีอิทธิพลมีดังนี้
- การติดตามและข้อมูลเชิงลึก: ทำ log tracing ครอบคลุมทุกแอปและไมโครเซอร์วิสภายใน Netflix เพื่อทำความเข้าใจการสื่อสารระหว่างบริการ ช่วยดีบักปัญหา และตอบคำขอสนับสนุน
- การติดตามปฏิสัมพันธ์ของผู้ใช้: ติดตามการโต้ตอบของผู้ใช้หลายล้านครั้ง เช่น การเล่นวิดีโอ การค้นหา และการมีส่วนร่วมกับคอนเทนต์ เพื่อปรับปรุงอัลกอริทึมการแนะนำของ Netflix แบบเรียลไทม์ และมอบข้อมูลเชิงลึกเพื่อยกระดับประสบการณ์ผู้ใช้โดยรวม
- การเปิดตัวฟีเจอร์และการวิเคราะห์ประสิทธิภาพ: ติดตามการเปิดตัวและประสิทธิภาพของฟีเจอร์ผลิตภัณฑ์ใหม่ ช่วยให้วิศวกรของ Netflix วัดได้ว่าผู้ใช้โต้ตอบกับฟีเจอร์อย่างไร และสนับสนุนการตัดสินใจปรับปรุงในอนาคตบนฐานข้อมูล
- การติดตามและเพิ่มประสิทธิภาพ asset impression: ติดตามการแสดงผลของแอสเซ็ตเพื่อให้มั่นใจว่าคอนเทนต์และแอสเซ็ตถูกส่งมอบอย่างมีประสิทธิภาพ พร้อมให้ feedback แบบเรียลไทม์เพื่อการปรับให้เหมาะสม
- การเรียกเก็บเงินและการจัดการการสมัครสมาชิก: จัดเก็บข้อมูลย้อนหลังที่เกี่ยวข้องกับการเรียกเก็บเงินและการจัดการการสมัครสมาชิก เพื่อรับประกันความถูกต้องของประวัติธุรกรรมและสนับสนุนการสอบถามจากฝ่ายบริการลูกค้า
การปรับปรุงในอนาคต
เมื่อ use case มีการเปลี่ยนแปลงและความจำเป็นในการทำ abstraction ให้คุ้มค่าด้านต้นทุนมากขึ้นเพิ่มสูงขึ้น Netflix วางแผนจะปรับปรุงบริการนี้อย่างมากในอีกไม่กี่เดือนข้างหน้า บางส่วนมีดังนี้
- Tiered storage เพื่อประสิทธิภาพด้านต้นทุน: รองรับการย้ายข้อมูลที่เก่ากว่าและถูกเข้าถึงน้อยไปยัง object storage ที่มีราคาถูกกว่าแต่ใช้เวลานานกว่าจะถึง first byte ซึ่งอาจช่วยประหยัดค่าใช้จ่ายให้ Netflix ได้หลายล้านดอลลาร์
- Dynamic event bucketing: แทนที่จะใช้การตั้งค่าที่ค่อนข้างคงที่ขณะ provisioning namespace ระบบจะรองรับการแบ่งคีย์แบบเรียลไทม์ไปยังพาร์ทิชันขนาดที่เหมาะสมที่สุดขณะ event ไหลเข้ามาแบบสตรีมมิง กลยุทธ์นี้มีข้อดีสำคัญคือช่วยลดต้นทุนรวมของ read amplification ด้วยการ ไม่ แบ่งพาร์ทิชันให้กับ
time_series_idที่ ไม่จำเป็นต้อง แบ่งพาร์ทิชัน นอกจากนี้ใน Cassandra 4.x ยังมีการปรับปรุงสำคัญสำหรับการอ่านชุดย่อยของข้อมูลจากพาร์ทิชันขนาดใหญ่ จึงอาจลดความจำเป็นในการแบ่งชุดข้อมูลทั้งหมดแบบเชิงรุกล่วงหน้า - Caching: ใช้ประโยชน์จากความเป็น immutable ของข้อมูลเพื่อแคชแต่ละช่วงเวลาอย่างชาญฉลาด
- การนับและการรวมผลอื่น ๆ: ผู้ใช้บางรายสนใจเพียงจำนวน event ภายในช่วงเวลาที่กำหนด แทนที่จะดึงข้อมูล event ทั้งหมด
บทสรุป
- TimeSeries Abstraction เป็นองค์ประกอบสำคัญของโครงสร้างพื้นฐานข้อมูลออนไลน์ของ Netflix โดยรองรับทั้งการตัดสินใจแบบเรียลไทม์และระยะยาว
- เมื่อ Netflix ขยายไปยังโดเมนใหม่ ๆ TimeSeries Abstraction จะยังคงเป็นองค์ประกอบหลักของแพลตฟอร์มและช่วยขยายขีดความสามารถของการสตรีมและสิ่งที่มากกว่านั้น
ความเห็นของ GN⁺
- ความเชี่ยวชาญของ Netflix ในการประมวลผลข้อมูลอนุกรมเวลาปริมาณมหาศาลอย่างเสถียรผ่าน TimeSeries abstraction นั้นน่าประทับใจ เพราะสามารถได้ทั้งความสามารถในการขยายระบบ ความยืดหยุ่น และความคุ้มค่าด้านต้นทุนไปพร้อมกัน โดยเฉพาะเทคนิคที่ปรับให้เหมาะกับลักษณะข้อมูลและรูปแบบการเข้าถึง เช่น time-based partitioning, write buffering และ dynamic compaction ที่โดดเด่นมาก
- สิ่งนี้ไม่ใช่เพียง time-series DB ธรรมดา แต่เป็นชั้น abstraction ที่ช่วยให้ใช้สตอเรจอย่าง Cassandra และ Elasticsearch ได้อย่างยืดหยุ่น พร้อมมีระบบควบคุมสำหรับ provisioning และปฏิบัติการโครงสร้างพื้นฐานให้เหมาะกับลักษณะเวิร์กโหลด ทำให้ผู้ใช้สามารถซ่อนความซับซ้อนและโฟกัสกับข้อมูลได้
- ปัจจุบันระบบรองรับข้อมูลระดับเพตะไบต์และประมวลผลได้ 15 ล้าน event ต่อวินาที จึงนับเป็นตัวอย่างที่น่าเรียนรู้สำหรับองค์กรที่ต้องการสร้างไปป์ไลน์ข้อมูลอนุกรมเวลาประสิทธิภาพสูง โดยชี้ให้เห็นว่า สำหรับบริการขนาดใหญ่ต้องคำนึงถึงทั้งปริมาณและความเร็วของข้อมูล รวมถึงต้นทุนอย่างรอบด้าน
- ระบบนี้ถูกใช้งานอย่างหลากหลายในพื้นที่สำคัญของธุรกิจ Netflix เช่น tracing การวิเคราะห์พฤติกรรมผู้ใช้ และการจัดการการเรียกเก็บเงิน แสดงให้เห็นว่าข้อมูลอนุกรมเวลาเป็นแรงขับเคลื่อนของการตัดสินใจบนฐานข้อมูลและนวัตกรรมบริการ ไม่ได้เป็นเพียงการทำ logging แต่ยังเป็นรากฐานของบริการที่อิง ML/AI เช่นระบบแนะนำแบบเรียลไทม์
- แผนการพัฒนาในอนาคต เช่น tiered storage, dynamic partitioning และการรวมผลรูปแบบต่าง ๆ สะท้อนให้เห็นถึงความตั้งใจในการพัฒนาอย่างต่อเนื่อง เพื่อตอบสนองต่อความต้องการทางธุรกิจที่เปลี่ยนแปลงรวดเร็ว และหวังว่าความรู้ที่สั่งสมระหว่างทางจะถูกแบ่งปันผ่านโอเพนซอร์สหรือช่องทางอื่น ๆ
ยังไม่มีความคิดเห็น