ปัญหาของสเปก Iceberg
- ปัญหาร้ายแรงของสเปก Iceberg: สเปก Iceberg ไม่ใช่ความพยายามอย่างจริงจังในการแก้ปัญหาเมทาดาทาของ data lake ขนาดใหญ่
- บทเรียนจากประวัติศาสตร์: ในส่วนแรก ผู้เขียนย้อนกลับไปดูประวัติศาสตร์เพื่อเรียนรู้บทเรียนจากอดีต และแนะนำ "ปัญหาการจัดการพื้นที่" ที่ฐานข้อมูลต้องแก้ไข
- องค์ประกอบของปัญหา:
- การกระจายตัวของพื้นที่
- การควบคุมการทำงานพร้อมกันแบบละเอียด
- ความเป็นอะตอมมิกข้ามหลายอ็อบเจ็กต์
- ความไม่สอดคล้องเชิงอิมพีแดนซ์ระหว่างแถวกับไฟล์
- การเข้าถึงเมทาดาทาด้วย latency ต่ำและ throughput สูง
- ความสำคัญของฟอร์แมตแบบเปิด: เห็นด้วย 100% กับการใช้ฟอร์แมตแบบเปิดในทุกชั้นของสแตก และตื่นเต้นเป็นพิเศษกับการใช้ Parquet เป็นฟอร์แมตจัดเก็บมาตรฐานสำหรับข้อมูลแบบตาราง
- ความต่างระหว่างไฟล์ Parquet กับตารางฐานข้อมูล: การมีไฟล์ Parquet มารวมกันไม่ได้หมายความว่านั่นคือ table ของฐานข้อมูล table ของฐานข้อมูลเป็นมากกว่าชุดของแถวธรรมดา
สรุปปัญหาเมทาดาทา
- ปัญหาการจัดการพื้นที่: ย้ำอีกครั้งถึงปัญหาหลายอย่างที่ฐานข้อมูลต้องแก้
- ความจำเป็นของเมทาดาทา: หากต้องการให้ไฟล์ Parquet หลายไฟล์ดูเหมือน table ของฐานข้อมูล จำเป็นต้องมีเมทาดาทาดังต่อไปนี้:
- รายการตำแหน่งของไฟล์ทั้งหมดที่ประกอบเป็น table
- เมทาดาทาแบบคร่าว ๆ ของแต่ละไฟล์
- กลไกควบคุมทรานแซกชันสำหรับการเพิ่มหรือลบไฟล์
- วิธีที่ทำให้ schema ของ table พัฒนาไปได้
- การค้นหาตำแหน่งไฟล์: หากจะปฏิบัติต่อชุดไฟล์ Parquet ให้เป็น table เดียว ต้องมีกลไกสำหรับค้นหาไฟล์เหล่านั้น
- ความสำคัญของเมทาดาทา: แต่ละไฟล์ต้องมีเมทาดาทาเพิ่มเติมเพื่อค้นหาแถวที่น่าสนใจได้อย่างรวดเร็ว
ไฟล์ Parquet และตารางฐานข้อมูล
- คำจำกัดความของไฟล์ Parquet: Parquet ให้ฟอร์แมตข้อมูลแบบตารางที่อธิบายตัวเองได้
- คำจำกัดความของตารางฐานข้อมูล: table ของฐานข้อมูลไม่ได้เป็นเพียงชุดของแถว แต่ต้องมีเมทาดาทาหลายส่วนและการควบคุมทรานแซกชัน
- เงื่อนไขในการใช้ไฟล์ Parquet ให้เหมือน table:
- รายการตำแหน่งไฟล์
- เมทาดาทาของแต่ละไฟล์
- กลไกควบคุมทรานแซกชันสำหรับการเพิ่มและลบไฟล์
- วิธีการวิวัฒนาการของ schema ของ table
- ความแตกต่างระหว่างไฟล์กับ table: ต่อให้ไฟล์ Parquet มี layout ของคอลัมน์เหมือนกัน ก็ไม่ได้ทำให้มันดูเหมือน table ของฐานข้อมูล
ไฟล์ manifest และ list
- กระบวนการเพิ่มข้อมูล: หากไคลเอนต์ Iceberg ต้องการเพิ่มข้อมูลเข้า table จะต้องผ่านขั้นตอนต่อไปนี้:
- เขียนไฟล์ Parquet หนึ่งไฟล์หรือมากกว่านั้นไปยังตำแหน่งที่กำหนด เช่น S3
- เขียนไฟล์ manifest ที่ชี้ไปยังไฟล์ที่สร้างในขั้นตอนที่ 1
- เขียน manifest list ใหม่
- รูปแบบของไฟล์ manifest: ไฟล์ manifest และ list อยู่ในรูปแบบ AVRO ซึ่งถูกบีบอัดและอธิบายตัวเองได้
- เนื้อหาของไฟล์ manifest: ไฟล์ manifest ประกอบด้วยตัวชี้ไปยังไฟล์ Parquet และเมทาดาทาของแต่ละคอลัมน์
- ปัญหาขนาดของเมทาดาทา: การเก็บเมทาดาทาแบบนี้ทำให้ขนาดใหญ่เกินจำเป็น และไม่สามารถบีบอัดโดยรับรู้ค่าสตริงร่วมกันระหว่างไฟล์ได้
ภาระของไคลเอนต์ที่เพิ่มขึ้น
- ความรับผิดชอบของไคลเอนต์: ตลอดทั้งสเปก Iceberg ไคลเอนต์ต้องจัดการงานบันทึกข้อมูลจำนวนมหาศาลเพื่อรองรับการเปลี่ยนแปลงที่เรียบง่าย
- ปัญหาความถูกต้องของเมทาดาทา: หากไคลเอนต์เขียนบางส่วนผิด การ commit snapshot ใหม่ต้องมีการตรวจสอบอย่างเข้มงวด และต้องยืนยันว่าข้อมูล manifest ถูกเขียนไว้อย่างถูกต้อง
- ปัญหาด้านความปลอดภัย: เนื่องจากไคลเอนต์ต้องเขียน manifest list ที่ชี้ไปยังไฟล์ manifest ทั้งหมด ตำแหน่งของไฟล์ทั้งหมดใน S3 จึงรั่วไหลออกมา
- ความสำคัญของความปลอดภัยของข้อมูล: เนื่องจากข้อมูลมีมูลค่าสูง จึงควรตั้งคำถามว่าเหตุใดสเปกนี้จึงไม่ให้ความสำคัญกับความปลอดภัยเป็นอันดับแรก
ข้อบกพร่องของความปลอดภัยระดับแถว
- ความจำเป็นของความปลอดภัยระดับแถว: แม้แต่ในประเทศที่กำกับดูแลหลวมอย่างสหรัฐฯ ก็ยังต้องมีความปลอดภัยระดับแถวเพื่อปกป้องข้อมูลอ่อนไหว
- GDPR ของสหภาพยุโรป: ในยุโรป จำเป็นต้องระมัดระวังเรื่องการเข้าถึงข้อมูลมากยิ่งขึ้นเพราะกฎหมายอย่าง GDPR
- ปัญหาการเข้าถึงข้อมูลของไคลเอนต์: ไคลเอนต์สามารถเพิ่มข้อมูลเข้า table ได้ แต่ไม่สามารถจำกัดการเข้าถึงข้อมูลที่มีอยู่แล้วได้
- ความร้ายแรงของปัญหาด้านความปลอดภัย: การที่สเปกไม่ให้ความสำคัญกับความปลอดภัยเป็นอันดับต้น ๆ ควรกระตุ้นให้ตั้งคำถามถึงมูลค่าของข้อมูลใน data lake
บทบาทของไฟล์เมทาดาทา
- การเขียนไฟล์เมทาดาทา: หลังจากไคลเอนต์เขียนไฟล์ Parquet แล้ว จะต้องสร้างไฟล์ manifest อ่าน manifest list เดิม สร้าง manifest list ใหม่ แล้วจึง commit ข้อมูล
- กระบวนการ commit: การ commit ทำได้โดยการเขียนไฟล์เมทาดาทา (
<prefix>.metadata.json)
- การเลือกใช้รูปแบบ JSON: ไม่ชัดเจนว่าทำไมไฟล์เมทาดาทาจึงใช้รูปแบบ JSON ซึ่งให้ความรู้สึกเหมือน "การออกแบบโดยคณะกรรมการ"
- ความซ้ำซ้อนของเมทาดาทา: ไฟล์เมทาดาทาจะแสดงรายการ snapshot ทั้งหมด ซึ่งทำให้สิ้นเปลืองพื้นที่จากการซ้ำของข้อมูล
ความซับซ้อนของกระบวนการ commit
- ปัญหาความเป็นอะตอมมิก: ต้องทำให้ไฟล์เมทาดาทาใหม่กลายเป็นไฟล์ล่าสุด และแทนที่ไฟล์เมทาดาทาเดิมแบบอะตอมมิก
- ความซับซ้อนของขั้นตอน commit: เพื่อ commit เมทาดาทาเวอร์ชันใหม่ V+1 จำเป็นต้องทำขั้นตอนต่อไปนี้:
- สร้างไฟล์เมทาดาทา table ใหม่โดยอิงจากเมทาดาทาปัจจุบัน
- เขียนเมทาดาทา table ใหม่ลงในไฟล์ที่ไม่ซ้ำกัน
- ส่งคำขอไปยัง metastore เพื่อแทนที่ตัวชี้เมทาดาทาของ table จาก V เป็น V+1
- การจัดการเมื่อสลับล้มเหลว: หากการสลับล้มเหลว แสดงว่ามีนักเขียนรายอื่นสร้าง V+1 ไปแล้ว ดังนั้นไคลเอนต์ต้องย้อนกลับไปเริ่มที่ขั้นตอนที่ 1
- ปัญหาของ race condition: เมื่อไคลเอนต์หลายตัวแข่งขันกัน ไคลเอนต์ต้องอ่านไฟล์เมทาดาทาที่ไคลเอนต์ก่อนหน้าเขียนไว้ใหม่ และสร้าง manifest list กับไฟล์เมทาดาทาขึ้นมาใหม่อีกครั้ง
ปัญหาของ optimistic concurrency control
- ข้อเท็จจริงของ concurrency: หากไม่คาดว่าจะมีการแข่งขันกันแย่งทรัพยากร จะใช้กลไก concurrency แบบใดก็ไม่ค่อยสำคัญ
- กรณีที่คาดว่าจะมีการแข่งขัน: หากไคลเอนต์สองตัวพยายามเปลี่ยนค่าเดียวกัน ควรใช้กลไกการล็อก
- ข้อจำกัดของ optimistic concurrency control: ใน Iceberg การเขียนพร้อมกันสองครั้งจะชนกันเสมอ ซึ่งเป็นผลจากวิธีที่สเปกถูกออกแบบ
- ความหมายของการล็อกที่แย่ที่สุด: ระบบนี้ใช้ semantics การล็อกที่แย่ที่สุดกับเมทาดาทา ทั้งที่หากต้องการเพียงเพิ่มข้อมูล ก็ไม่จำเป็นต้องให้ไคลเอนต์ประสานงานกัน
ข้อจำกัดของการสลับเมทาดาทา
- การรวมศูนย์เมทาดาทา: การรวมเมทาดาทาของ table ไว้ในไฟล์เดียวสร้างจุดแข่งขันเพียงจุดเดียวสำหรับการเขียนทั้งหมด
- ภาระของไคลเอนต์เมื่อ retry: หากไคลเอนต์ล้มเหลว จะต้องอ่านข้อมูลที่ไคลเอนต์ก่อนหน้าเขียนไว้ และสร้าง manifest list กับไฟล์เมทาดาทาใหม่
- ความเร็วของการสลับเมทาดาทา: บริการที่ทำหน้าที่สลับเมทาดาทาต้องรองรับการ retry ด้วย ซึ่งทำให้ประสิทธิภาพลดลง
- จำนวน commit ที่จำกัด: ด้วยการทำ concurrency แบบง่าย จำนวน commit จึงถูกจำกัดด้วยเวลาที่ใช้ในการแทนที่ไฟล์เมทาดาทาแบบอะตอมมิก
ความจำเป็นของฐานข้อมูล
- การค้นหาตำแหน่งของไฟล์เมทาดาทา: snapshot ของ table ใน Iceberg ถูกอธิบายได้ครบถ้วนด้วยไฟล์ metadata.json
- ความขัดแย้งในแนวคิด: Iceberg พยายามกำหนดรูปแบบเมทาดาทาด้วยไฟล์ล้วน ๆ แต่สุดท้ายก็ยังต้องการฐานข้อมูล
- ข้อดีของฐานข้อมูล: ฐานข้อมูลสมัยใหม่สามารถรองรับการเขียนได้หลายแสนครั้ง และขยายแบบกระจายได้
- การเปรียบเทียบระหว่างระบบไฟล์กับฐานข้อมูล: การเก็บเมทาดาทาไว้ในฐานข้อมูลมีประสิทธิภาพกว่าการเก็บไว้ในไฟล์
การแตกเป็นชิ้นและการพองตัวของเมทาดาทา
- การเติบโตของไฟล์ metadata.json: ไฟล์ metadata.json ชี้ไปยัง snapshot ล่าสุด และไฟล์เมทาดาทาแต่ละไฟล์มีตัวชี้ย้อนกลับไปยัง snapshot ก่อนหน้า
- การเพิ่มขึ้นอย่างต่อเนื่องของเมทาดาทา: เมทาดาทาเพิ่มขึ้นอย่างต่อเนื่อง ซึ่งส่งผลเสียต่อประสิทธิภาพของ data lake
- ความจำเป็นในการทำความสะอาดเมทาดาทาเป็นประจำ: หากมีการเพิ่มข้อมูลเข้า data lake อย่างต่อเนื่อง ก็ต้องทำความสะอาดเมทาดาทา
- ต้นทุนของคำขอ HTTP: ในกระบวนการลบไฟล์เมทาดาทาจะเกิดคำขอ HTTP ซึ่งอาจก่อให้เกิดค่าใช้จ่าย
การอ่านข้อมูลและการวางแผนคิวรี
- บทบาทของไฟล์ manifest: ไฟล์ manifest มีเมทาดาทาเกี่ยวกับไฟล์ Parquet
- ความซับซ้อนของการวางแผนคิวรี: เพื่อรันคิวรี ต้องอ่าน manifest list และไฟล์ manifest ตามลำดับ
- ปัญหาด้านต้นทุน: การอ่านจาก S3 มีต้นทุน ซึ่งส่งผลต่อความเร็วในการรันคิวรี
- ปัญหาการแตกกระจายของเมทาดาทา: เมื่อเมทาดาทาแตกกระจาย การวางแผนคิวรีจะซับซ้อนขึ้นและเข้าถึงข้อมูลได้ยากขึ้น
การแคชและความยากของการวางแผนคิวรี
- การแคช manifest: สามารถแคช manifest ได้ แต่ไม่มีประสิทธิภาพเพราะขนาดของเมทาดาทาใหญ่ขึ้นเรื่อย ๆ
- การทำให้แคชยังใช้ได้อยู่: ต้องตรวจสอบว่าแคชยังเป็นข้อมูลล่าสุดหรือไม่ ซึ่งก่อให้เกิดต้นทุนและความซับซ้อนเพิ่มเติม
- ภาระของไคลเอนต์: ไคลเอนต์ทุกตัวต้องแคชเมทาดาทา ซึ่งทำให้เกิดคำขอ HTTP หลายล้านครั้ง
- ความซับซ้อนที่เพิ่มขึ้น: การใช้งาน data lake ซับซ้อนมากขึ้น และต้องมีโซลูชันเพิ่มเติมเพื่อแก้ปัญหา
บทสรุปของแนวคิด
- คำวิจารณ์ต่อแนวคิดนี้: สเปก Iceberg ไม่ใช่สเปกที่จริงจังสำหรับเมทาดาทาของ data lake และมีปัญหาหลายประการ
- สรุปปัญหา: Iceberg เพิ่มเมทาดาทาด้วยงานแบบ O(n) ไม่สามารถจัดการ commit ข้ามตารางได้ และไม่สามารถแก้ปัญหาเมทาดาทาพองตัวได้
- ข้อจำกัดด้านการสเกล: Iceberg ไม่เหมาะกับการสเกล และผลักความซับซ้อนมากเกินไปไปยังไคลเอนต์
- คำถามต่ออุตสาหกรรม: ตั้งคำถามว่าเหตุใดปัญหาเช่นนี้จึงเกิดขึ้นในอุตสาหกรรม IT
ยังไม่มีความคิดเห็น