พอพูดถึงคำว่า Data Lakehouse ทีไร ภาพแรกที่ผุดขึ้นมาในหัวคือ Apache Spark, Apache Iceberg, Delta Lake แล้วก็ Cluster ตัวเป้งๆ ที่ต้องมีทีมคอย Maintain กันยาวๆ ทั้งที่จริงแล้วหลายๆ Use Case มันไม่ได้ต้องการขนาดนั้นเลย

ไม่ใช่ทุก Data Platform ที่ต้องใช้ Spark-based Lakehouse
ทุกวันนี้พอพูดถึง Lakehouse คนก็มักจะนึกถึง Apache Iceberg หรือ Delta Lake เป็นอันดับแรกๆ ซึ่งก็ไม่แปลกเพราะสองตัวนี้ครองตลาดจริง แต่ทั้งคู่ถูกออกแบบมาให้ทำงานคู่กับ Compute Engine ขนาดใหญ่แบบ Spark, Trino หรือ Flink ซึ่งเหมาะกับองค์กรที่มีข้อมูลระดับ Petabyte มีทีม Data Engineer คอยดูแล Cluster ตลอดเวลา และต้องการ Concurrent Write จากหลายทีมพร้อมกัน

แต่ถ้าเราเป็นทีมเล็กๆ หรือกำลังสร้าง Data Platform ขนาด Small ถึง Medium ที่ข้อมูลอาจจะอยู่แค่หลัก GB ไปจนถึง TB ต้นๆ การแบก Spark Cluster มาทั้งก้อนตั้งแต่วันแรกก็ดูจะเกินความจำเป็นไปหน่อยนะครับ ทั้งค่า Cluster ที่วิ่งตลอดเวลา ทั้ง Operational Overhead ที่ต้องมานั่งดูแล Job, Tuning Memory, จัดการ Autoscaling เอง สุดท้ายทีมเล็กๆ ก็อาจจะเสียเวลาไปกับการดูแล Infrastructure มากกว่าการทำ Data Product จริงๆ ซะอีก ยังไม่รวมที่ Spark จะทำงานได้ช้ามากถ้าต้องไปทำงานกับข้อมูลขนาดเล็ก

เอาละ แล้วถ้าไม่ใช้ Spark-based Lakehouse จะมีทางเลือกอะไรบ้าง วันนี้เลยจะขอพาไปรู้จักกับ DuckLake ตัวเลือกที่กำลังมาแรงในกลุ่มคนที่อยากได้ Lakehouse Features แต่ไม่อยากแบก Cluster กันดีกว่าครับ
DuckLake คืออะไร
DuckLake is an integrated data lake and catalog format

พูดง่ายๆ DuckLake คือ Table Format ตัวใหม่จากทีม DuckDB Labs เจ้าของ DuckDB นั่นแหละครับ จุดที่ต่างจาก Iceberg หรือ Delta Lake อย่างชัดเจนคือเรื่อง Metadata เพราะ Iceberg กับ Delta Lake เก็บ Metadata (Manifest, Snapshot, Transaction Log) เป็นไฟล์ JSON หรือ Avro กระจัดกระจายอยู่บน Object Storage เอง ซึ่งพอไฟล์เยอะขึ้นเรื่อยๆ การ List และ Parse ไฟล์พวกนี้ก่อน Query ทุกครั้งก็กลายเป็นคอขวดได้

แต่ DuckLake เลือกเก็บ Metadata พวกนี้ไว้ใน SQL Database แทน จะเป็น PostgreSQL, MySQL, SQLite หรือแม้แต่ DuckDB เองก็ได้ ส่วนข้อมูลจริงยังคงเก็บเป็น Parquet บน Object Storage เหมือนเดิม พอ Metadata อยู่ในฐานข้อมูลที่รองรับ ACID Transaction อยู่แล้ว DuckLake ก็เลยได้ Feature ของ Lakehouse มาแบบครบๆ ทั้ง ACID Transaction, Time Travel, Schema Evolution, และ Partitioning โดยไม่ต้องมานั่งเขียน Manifest File เองเลยครับ
จุดที่ผมชอบคือ ประโยคที่ทีม DuckDB Labs ใช้อธิบายตัวเองตรงๆ ว่า
DuckLake delivers advanced data lake features without traditional lakehouse complexity by using Parquet files and your SQL database
แปลว่าสิ่งที่ต้องมีจริงๆ แค่ Database สักตัวไว้เป็น Catalog กับที่เก็บไฟล์ Parquet เท่านั้น ไม่ต้องมี Spark Cluster หรือ Metastore Service แยกต่างหากเลยครับ
ตัวอย่างการ Attach DuckLake
ATTACH 'ducklake:postgres:dbname=ducklake_catalog host=rds-endpoint' AS my_ducklake (DATA_PATH 's3://my-bucket/curated/');USE my_ducklake;SELECT * FROM my_table;
แค่นี้ DuckDB ก็จะรู้แล้วว่า Catalog อยู่ที่ Postgres ตัวไหน และข้อมูล Parquet จริงๆ อยู่ที่ S3 Path ไหน ครับ
Let’s Try Implement: DuckLake บน AWS
ทีนี้พอเข้าใจ DuckLake แล้ว มาดูกันว่าถ้าจะเอามาวางเป็น Data Platform จริงบน AWS แบบที่เน้น Cost-efficient ที่สุดสำหรับทีม Small ถึง Medium จะหน้าตาเป็นยังไงครับ ผมออกแบบ Architecture นี้ไว้โดยเลือกใช้ Serverless แทบทั้งหมด

Data Sources ฝั่ง Input ก็มีทั้ง App Database, SaaS API/Events, หรือไฟล์ CSV/Log ทั่วไป
Orchestration ใช้ AWS Step Functions แบบ Express Workflow เพราะราคาคิดเป็น Sub-cent ต่อ Execution เหมาะกับ Pipeline ที่รันสั้นๆ บ่อยๆ ตัว Step Functions จะคอยสั่ง Lambda แต่ละตัวให้ทำงานตามลำดับ
Compute เป็น Lambda ทั้งหมด 4 ตัว แบ่งหน้าที่กันชัดเจน
- Ingest ดึงข้อมูลจาก Source มาลง S3 Raw Zone
- Transform รัน DuckDB พร้อม Extension
ducklakeแปลงข้อมูลเป็น Parquet ลง S3 Curated Zone แล้ว Update Catalog ที่ RDS - Compact/Maintain รันตามรอบ Schedule ไว้ Compact ไฟล์เล็กๆ และ Expire Snapshot เก่า เพราะ DuckLake ก็ยังต้องการ Maintenance แบบนี้อยู่เพื่อให้ Query เร็ว
- Query ไว้ตอบ SQL Query แบบ Ad-hoc ให้ฝั่ง Consumer
ข้อดีของการใช้ Lambda ทั้งหมดคือ Pay-per-invocation ไม่มี Idle Cost เลย แต่ก็ต้องรู้ Limit ไว้ด้วยนะครับว่า Lambda รันได้สูงสุด 15 นาที Memory 10GB และ /tmp อีก 10GB ถ้า Query ไหนหนักเกินนี้ค่อยผลักไปรันบน Fargate Task แทน


Consumption แบ่งเป็นสองทางตามกลุ่มผู้ใช้ ฝั่ง Notebook หรือ Internal App ที่อยากยิง SQL แบบ Programmatic ก็ผ่าน API Gateway ไปเรียก Lambda Query ส่วนฝั่ง Business User ที่อยากได้ Dashboard แบบ Point-and-click ผมใส่ Apache Superset รันบน Fargate เข้าไป โดย Superset ต่อ DuckDB ผ่าน duckdb-engine ตรงๆ แล้ว ATTACH Catalog ของ DuckLake เลย ไม่ต้องผ่าน Lambda อีกชั้นด้วยซ้ำ ส่วน Metastore ของ Superset เองก็ใช้ RDS ตัวเดียวกันแค่แยก Schema ประหยัดไปอีกก้อนหนึ่งครับ

ทำไมเลือก Superset ไม่ใช้ Athena หรือ Redshift ไปเลย
พออ่านมาถึงตรงนี้หลายคนอาจจะสงสัยว่า ทำไมไม่ใช้ Athena หรือ Redshift Spectrum ต่อเข้ากับ S3 ไปเลย ในเมื่อทั้งคู่ก็เป็น Serverless Query Engine ของ AWS เองเหมือนกัน คำตอบสั้นๆ คือทั้ง Athena และ Redshift Spectrum ผูกกับ AWS Glue Data Catalog เป็นหลัก ซึ่งเข้าใจ Table Format แบบ Iceberg หรือ Hive Style เป็นหลัก แต่ไม่ได้เข้าใจ Catalog ของ DuckLake ที่เก็บอยู่ใน Postgres โดยตรง ถ้าจะใช้จริงต้องมี Step แปลง Metadata จาก DuckLake ไปเป็น Iceberg ก่อน ซึ่งเป็นการเพิ่ม Moving Part เข้ามาโดยไม่จำเป็น ทั้งที่จุดขายของ DuckLake คือการไม่ต้องมี Catalog Service แยกต่างหากตั้งแต่แรก (หวังว่าอนาคต Athena และ Redshift จะสามารถอ่านได้นะ หลังจากที่ AWS ซื้อกิจการ DuckDB Labs ไปแล้ว)

พอเทียบกันแล้ว Superset ต่อ DuckDB ตรงๆ DuckDB คือ Engine ตัวเดียวกับที่เขียนข้อมูล DuckLake ขึ้นมาตั้งแต่แรก ไม่มี Step แปลง Format ระหว่างทางเลย แถมได้ Dashboard UI มาในตัวเดียวจบ ไม่ต้องแยกเป็น Query Engine หนึ่งตัวกับ BI Tool อีกตัว และค่าใช้จ่ายก็คุมง่ายกว่าเพราะเป็น Container ราคาคงที่ที่ Scale-to-zero ได้ ไม่ใช่ Pay-per-TB-scanned แบบ Athena ที่ถ้า Dashboard Refresh บ่อยๆ โดยไม่ทำ Partition ให้ดี ค่าใช้จ่ายอาจจะพุ่งแบบไม่ทันตั้งตัวได้เหมือนกันครับ

แต่ช้าก่อน! Fargate เป็น Container ที่รันค้างไว้ ไม่ใช่ Pay-per-invocation แบบ Lambda จุดนี้เลยเป็นจุดเดียวใน Architecture ที่มี Cost แบบ Always-on ผมเลยแนะนำให้ทำ Scale-to-zero ด้วย Application Auto Scaling ตั้ง Scheduled Action ให้ Desired Count เป็น 1 ตอนเข้างาน แล้วปรับเป็น 0 ตอนเลิกงานกับวันหยุด ใครอยากได้แบบ Advanced กว่านั้นก็ทำ Wake-on-request ผ่าน Lambda เช็คสถานะ Service แล้วสั่ง Start ให้อัตโนมัติเมื่อมีคน Request เข้ามาได้เหมือนกัน แบบนี้ทีม Small-Medium ก็จะจ่ายค่า Fargate แค่ช่วงที่มีคนใช้งานจริงๆ เท่านั้นเองครับ
ผมอาจจะไม่ได้เขียนลงรายละเอียดเกี่ยวกับ Deploy Ducklake on AWS มากนัก ผมมีทำ Github Repository เอาไว้ ซึ่งสามารถศึกษาหรือเอาไปลองเล่นได้เลย
สรุปให้ชัดๆ ว่าทำไม Architecture นี้ถึงประหยัด
เหตุผลที่ Architecture นี้มีความ Cost-efficient สูง มาจากปัจจัยเหล่านี้
- Lambda จ่ายแบบ Pay-per-invocation ไม่มี Idle Cost เลย
- Step Functions Express คิดเงินแบบ Sub-cent ต่อ Execution
- S3 ตั้ง Lifecycle Rule ย้ายข้อมูลเย็นไป Glacier ให้อัตโนมัติ
- RDS ใช้ Instance เล็กๆ ตัวเดียว ทำหน้าที่ทั้งเป็น Catalog ของ DuckLake และ Metastore ของ Superset ไปพร้อมกัน ไม่ได้มีความจำเป็นต้องใช้ Compute อะไรมาก
- Fargate (Superset) เป็นจุดเดียวในนี้ที่รันค้างไว้ แต่ก็ตั้ง Scale-to-zero นอกเวลาทำงานได้เหมือนกัน *แต่ถ้าทีมไหนไม่ได้มีความจำเป็นที่จะต้องใช้ Superset ในการ Query สามารถเชื่อมต่อเองได้ผ่าน CLI หรือ Local script ก็จะประหยัดตรงนี้ไปได้อีก
พูดง่ายๆ คือแทบไม่มีอะไรใน Architecture นี้ที่รันตลอดเวลาเลยครับ นอกจาก RDS และ Fargate ที่ก็ยังคุมด้วย Schedule ให้ประหยัดขึ้นได้อีกที
แล้ว Cost จริงๆ ประมาณเท่าไหร่
พูดมาเยอะเรื่อง Cost-efficient แล้ว ลองมาดูตัวเลขคร่าวๆ กันดีกว่าครับ ว่าสำหรับทีม Small-Medium ที่ข้อมูลอยู่หลัก GB ถึง TB ต้นๆ ค่าใช้จ่ายรายเดือนหน้าตาจะประมาณไหน (อิงราคาโซน US East, N. Virginia ซึ่งถูกที่สุด ส่วนภูมิภาคอื่นอาจแพงกว่านี้ 10-30% และตัวเลขจริงจะขยับตาม Data Volume กับความถี่ในการ Query ของแต่ละทีมด้วยนะครับ)
- Lambda + Step Functions Express: ทีมเล็กๆ ที่ Pipeline รันไม่บ่อยมาก มักจะอยู่ในหรือใกล้ Free Tier เลยครับ (Lambda ให้ฟรี 1 ล้าน Requests กับ 400,000 GB-seconds ต่อเดือน) ถ้าเกินก็ยังอยู่หลักไม่กี่ดอลลาร์ต่อเดือนเท่านั้น
- S3: Storage แบบ Standard อยู่ที่ประมาณ $0.023 ต่อ GB ต่อเดือน ถ้าตั้ง Lifecycle Rule ย้าย Raw Zone เก่าๆ ไป Glacier ก็ถูกลงไปอีก
- RDS db.t4g.micro (Postgres): ค่า Compute อยู่ที่ประมาณ $12-15 ต่อเดือน (ยังไม่รวม Storage อีกไม่กี่ดอลลาร์) ตัวเดียวรับหน้าที่ทั้ง DuckLake Catalog และ Superset Metastore เลย
- Fargate (Superset): ที่ Spec 0.5 vCPU / 1GB ถ้ารันตลอด 24/7 จะอยู่ที่ประมาณ $18 ต่อเดือน แต่ถ้าทำ Scale-to-zero เหลือแค่ช่วงเวลาทำงาน (Weekday 8 โมงเช้าถึง 5 โมงเย็น) จะลดลงเหลือประมาณ $5-6 ต่อเดือนเท่านั้นเอง

รวมๆ แล้วทีม Small-Medium น่าจะจ่ายอยู่ที่หลักสิบดอลลาร์ต่อเดือนเท่านั้นครับ ถูกกว่า Spark Cluster ขั้นต่ำที่ต้องมี 2 Worker วิ่งตลอดเวลาเยอะมาก ตัวเลขนี้เป็นแค่ตัวอย่างคร่าวๆ นะครับ อย่าลืมเช็คราคาจริงจาก AWS Pricing Calculator อีกทีก่อนตัดสินใจด้วยนะครับ
สรุป
DuckLake บวกกับ Architecture แบบ Lambda + Step Functions + Fargate Scale-to-zero แบบนี้ เหมาะมากสำหรับทีมหรือ Data Platform ขนาด Small ถึง Medium ที่อยากได้ Feature ของ Lakehouse จริงๆ ทั้ง ACID, Time Travel, Schema Evolution แต่ไม่อยากมีภาระดูแล Cluster หรือจ่ายค่า Infrastructure ที่ไม่ได้ใช้เต็มประสิทธิภาพ ถ้างบจำกัดและทีมเล็ก นี่คือทางเลือกที่คุ้มมากครับ
แต่ถ้าองค์กรมีข้อมูลระดับ Petabyte ต้องการ Concurrent Write จากหลายทีมพร้อมกันจำนวนมาก หรือ Ecosystem เดิมผูกกับ Spark/Trino/Presto อยู่แล้ว DuckLake ก็อาจจะยังไม่ใช่คำตอบที่เหมาะที่สุด เพราะ Ecosystem รอบๆ Iceberg หรือ Delta Lake ยังกว้างกว่ามากในตอนนี้
ทีนี้พอพูดถึง AWS โดยเฉพาะ หลายคนอาจจะคุ้นกับ Lakehouse แบบดั้งเดิมที่ใช้ Glue Data Catalog เก็บ Metadata แบบ Iceberg แล้วต่อกับ Athena, EMR, หรือ Redshift Spectrum ซึ่งเป็นสาย Spark/Presto Ecosystem เต็มตัว คำถามที่น่าคิดต่อคือแล้วระหว่าง DuckLake Architecture แบบที่เล่าวันนี้ กับ AWS Lakehouse สาย Iceberg แบบดั้งเดิม ต่างกันตรงไหนบ้างในแง่ Cost, Performance, และ Use Case ที่เหมาะสม เดี๋ยวขอเก็บไปเขียนเปรียบเทียบกันแบบละเอียดในบทความหน้านะครับ เพราะเนื้อหาน่าจะยาวพอจะแยกเป็นอีกบทความหนึ่งได้เลย 😆

Github Repo:
Leave a comment