01 สภาพแวดล้อมต้นทาง
จัดเตรียมสภาพแวดล้อม Snowflake ที่สะท้อนการติดตั้งใช้งานของลูกค้าจริง — 50 ล้านแถว, ไปป์ไลน์ dbt แบบ Medallion, producer การเดินทางที่ทำงานสด และแดชบอร์ด Superset สามตัว
จุดเริ่มต้น
โมดูล 00 เสร็จแล้ว: ติดตั้งชุดเครื่องมือแล้ว, บัญชีทดลองใช้ทั้งสองคลาวด์พร้อมใช้งาน,
โคลนรีโปแล้ว และสร้าง virtualenv ของ dbt-snowflake แล้ว โมดูลนี้ใช้เวลาประมาณ 45 นาที
และใช้เครดิต Snowflake ราว 2-4 เครดิต
ทำไม
คุณวางแผนการย้ายระบบโดยอ้างอิงต้นทางของเล่นไม่ได้ ตารางแบนตารางเดียวที่มีข้อมูลไม่กี่แถว
จะทำให้คุณข้ามทุกการตัดสินใจที่ทำให้การย้ายระบบจริงเป็นเรื่องยาก โมดูลนี้สร้างรูปทรงของ
การติดตั้งใช้งานของลูกค้าจริงขึ้นมาแทน: คอลัมน์ VARIANT ที่เก็บ JSON แบบกึ่งโครงสร้าง,
สตรีม CDC, task ตามกำหนดเวลา, ไปป์ไลน์ MERGE แบบ incremental และเลเยอร์ BI ที่อ่านอยู่
บนสุดของทั้งหมดนั้น ทุกอย่างที่กล่าวมาจะกลายเป็นการตัดสินใจย้ายระบบเฉพาะเรื่องในโมดูล 02 —
โมดูลนี้มีอยู่เพื่อให้คุณมีของจริงชี้ให้ดูเมื่อการตัดสินใจนั้นมาถึง แทนที่จะเป็นสิ่งที่เป็นนามธรรม
แนวคิด — เบื้องหลังการทำงาน
โครงสร้างพื้นฐาน (Terraform) การรัน setup.sh จะจัดเตรียม:
- Warehouse —
TRANSFORM_WH(SMALL, สำหรับ ELT) และANALYTICS_WH(MEDIUM, สำหรับ BI) บวกกับ resource monitor (ANALYTICS_WH_MONITOR) ที่จำกัดไว้ที่ 50 เครดิต/เดือน - ฐานข้อมูล —
NYC_TAXI_DBพร้อมสามสคีมา:RAW,STAGING,ANALYTICS - Role —
TRANSFORMER_ROLE,ANALYST_ROLE,DBT_ROLE,LOADER_ROLE
รูปทรงแบบ Medallion ข้อมูลเคลื่อนผ่านสามเลเยอร์ภายใน NYC_TAXI_DB:
- RAW —
TRIPS_RAW(50 ล้านแถวข้อมูลการเดินทางสังเคราะห์ รวมถึงคอลัมน์VARIANTชื่อTRIP_METADATAที่จำลอง telemetry ของแอป — นี่คือโจทย์การย้าย JSON) บวกกับตาราง มิติ (DIM_TAXI_ZONES,DIM_PAYMENT_TYPE,DIM_VENDOR) - STAGING — view ของ dbt ที่ทำความสะอาดชนิดข้อมูลและแผ่คอลัมน์
VARIANTออก - ANALYTICS — ตารางและโมเดล incremental ของ dbt:
fact_trips(50 ล้านแถว, กลยุทธ์MERGE), ตารางมิติสี่ตาราง และagg_hourly_zone_trips(ค่ารวมแบบ incremental)
มีอ็อบเจกต์ของ Snowflake สองตัวที่ทำให้ไปป์ไลน์นี้เดินหน้าด้วยตัวเอง โดยไม่ขึ้นกับ dbt:
TRIPS_CDC_STREAM— สตรีม Change Data Capture บนTRIPS_RAWCDC_CONSUME_TASK— อ่านสตรีมนั้นทุก 5 นาที (รันในRAWและถูกสั่ง resume ระหว่างการตั้งค่า) — และHOURLY_AGG_TASKที่รีเฟรชค่ารวมรายชั่วโมงทุกชั่วโมง (รันในSTAGINGและถูกสั่ง resume หลัง dbt build)
Superset แดชบอร์ดทั้งสามตัวอ่านจากสคีมา ANALYTICS ผ่าน ANALYTICS_WH — ไม่มีตัวใด
แตะ RAW หรือ STAGING โดยตรง เส้นทางการอ่านนั้นคือสิ่งที่คุณจะสร้างซ้ำบนฝั่ง ClickHouse
ในภายหลังของเวิร์กช็อป
ขั้นที่ 1 — ตั้งค่า credential
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake"
cp .env.example .env
# Edit .env with your Snowflake credentials
cp dbt/nyc_taxi_dbt/profiles.yml.example ~/.dbt/profiles.yml
# Edit ~/.dbt/profiles.yml with your account detailsทั้ง .env และ ~/.dbt/profiles.yml ถูก gitignore ไว้ — มันเก็บบัญชี Snowflake, ผู้ใช้ และ
รหัสผ่านของคุณ อย่า commit ไฟล์ทั้งสองเด็ดขาด
ขั้นที่ 2 — รันการตั้งค่า
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake"
source .env && ./setup.shคาดว่าจะใช้เวลา 5-10 นาที ซึ่งส่วนใหญ่หมดไปกับการสร้างข้อมูลการเดินทางสังเคราะห์
50 ล้านแถวด้วย TABLE(GENERATOR) setup.sh จัดเตรียมโครงสร้างพื้นฐานด้วย Terraform,
ใส่ข้อมูลตั้งต้นให้ TRIPS_RAW, รัน dbt build และเปิด Docker Compose (producer การเดินทาง
และ Superset) ในรอบเดียว
ขั้นที่ 3 — เริ่ม producer และ Superset
setup.sh เปิด Docker Compose ด้วยสภาพแวดล้อมที่ถูกต้อง, ลงทะเบียนการเชื่อมต่อ Snowflake
ใน Superset และนำเข้าแดชบอร์ดทั้งสามตัวโดยอัตโนมัติ
ไฟล์ ZIP แดชบอร์ดที่ commit ไว้ใน superset/dashboards/ มี sqlalchemy_uri ที่ถูกลบข้อมูล
ออกเป็นค่า placeholder (LAB_USER, MYORG-MYACCOUNT) การนำเข้าอัตโนมัติจะประทับ URI
ใหม่จาก .env ของคุณ ดังนั้นเรื่องนี้จะเกิดขึ้นแบบมองไม่เห็นเมื่อ setup.sh รัน หากคุณนำเข้า
ZIP ด้วยมือผ่าน UI ของ Superset แทน การเชื่อมต่อที่มันสร้างจะใช้ค่า placeholder เหล่านั้นและ
จะเชื่อมต่อไม่ได้ — ให้แก้การเชื่อมต่อภายหลังให้ชี้ไปที่บัญชี Snowflake จริงของคุณ
หากคุณต้องรีสตาร์ต Superset ด้วยมือ:
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake/superset"
docker-compose --env-file ../.env up -dแฟล็ก --env-file ../.env โหลดตัวแปรสภาพแวดล้อมจากไดเรกทอรีแม่
แดชบอร์ดสามตัวคือ Operations Command Center, Executive Weekly Report และ Driver & Quality Analytics (ช้าโดยเจตนา — มันเป็นเป้าหมายการเบนช์มาร์กของ ClickHouse ในภายหลัง ของเวิร์กช็อป) สำหรับการสร้างแดชบอร์ดฉบับเต็ม — แหล่งข้อมูล, ชาร์ต, ฟิลเตอร์ — ดู Superset บน Snowflake
ขั้นที่ 4 — ทำให้ dbt เป็นปัจจุบัน
producer การเดินทางแทรกข้อมูลราว 60 การเดินทาง/นาทีเข้าไปใน TRIPS_RAW อย่างต่อเนื่อง
เพื่อให้ fact_trips และ agg_hourly_zone_trips เป็นปัจจุบันขณะคุณทำงาน ให้รันลูปรีเฟรช
ของ dbt ในเทอร์มินัลอีกหน้าต่าง:
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake"
# Default: refresh every 5 minutes (auto-sources .env)
./scripts/run_dbt.sh
# Custom interval
./scripts/run_dbt.sh --interval 15m
# Run once and exit
./scripts/run_dbt.sh --once
# Include dbt tests after each run
./scripts/run_dbt.sh --test| แฟล็ก | ผล |
|---|---|
--interval <n> | เวลาระหว่างการรันแต่ละรอบ: 30s, 5m, 1h หรือจำนวนวินาทีเปล่า ๆ (ค่าเริ่มต้น: 5m) |
--once | รีเฟรชครั้งเดียวแล้วออก |
--test | รัน dbt test หลัง dbt run แต่ละครั้ง |
สคริปต์นี้รันแบบ incremental เสมอ — มันไม่เคยทำ --full-refresh ดังนั้นแถวที่ producer
แทรกเข้ามาจะถูกรักษาไว้ กด Ctrl-C เมื่อใดก็ได้เพื่อหยุดมัน ปล่อยให้มันรันในเทอร์มินัลของ
ตัวเองตลอดแล็บที่เหลือ — โมดูล 03 ยังต้องพึ่งมันอยู่
ขั้นที่ 5 — สำรวจคลังคิวรี
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake"ไดเรกทอรีคิวรี (workshop_public/snowflake_migration_lab/01-setup-snowflake/queries/)
เก็บไฟล์ SQL ที่มีคำอธิบายกำกับไว้เจ็ดไฟล์ แต่ละไฟล์รันกับสภาพแวดล้อม Snowflake ที่คุณ
เพิ่งสร้าง และแต่ละไฟล์มีโจทย์การย้ายระบบที่ตั้งใจไว้ ซึ่งโมดูล 02 จะแปลไปเป็น ClickHouse:
| คิวรี | โครงสร้างที่ใช้ | โจทย์การย้ายระบบ |
|---|---|---|
| Q1 | DATE_TRUNC, DATEADD | ต่างกันเล็กน้อยที่ syntax |
| Q2 | Window ROWS BETWEEN | เกือบเหมือนกันใน ClickHouse |
| Q3 | QUALIFY | รองรับในตัวใน ClickHouse ตั้งแต่ v24.5 — ที่นี่ยังเขียนใหม่เป็น subquery เพื่อความพอร์ตได้ |
| Q4 | LATERAL FLATTEN | ไม่มีสิ่งเทียบเท่า — ใช้ JSONExtract หรือแผ่ข้อมูลออกล่วงหน้า |
| Q5 | เส้นทางแบบโคลอนของ VARIANT | แทนที่ด้วย JSONExtractFloat/JSONExtractString |
| Q6 | MERGE INTO | ไม่มีสิ่งเทียบเท่า — ใช้ ReplacingMergeTree |
| Q7 | Snowflake Streams | เลิกใช้เมื่อตัดสวิตช์ — การเขียนสดไปที่ ClickHouse โดยตรงผ่าน producer |
เปิดแต่ละไฟล์และรันกับสภาพแวดล้อม Snowflake ของคุณก่อนไปต่อ บล็อกคอมเมนต์ในแต่ละคิวรี ร่างสิ่งเทียบเท่าใน ClickHouse ไว้แล้ว — โมดูล 02 คือที่ที่คุณจะเขียนและรันฝั่งนั้นจริง ๆ
วิธีตรวจสอบว่าคุณทำเสร็จแล้ว
cd "$(git rev-parse --show-toplevel)/workshop_public/snowflake_migration_lab/01-setup-snowflake"
source .env && ./scripts/verify_environment.shสิ่งนี้ตรวจสอบ:
- ฐานข้อมูลและสคีมา —
NYC_TAXI_DBมีอยู่ พร้อมRAW,STAGING,ANALYTICS - ตารางและข้อมูล —
TRIPS_RAWมีราว 50 ล้านแถว,FACT_TRIPSมีข้อมูล, ตารางมิติ มีอยู่ - สตรีม CDC —
TRIPS_CDC_STREAMมีอยู่บนTRIPS_RAW - task ตามกำหนดเวลา —
CDC_CONSUME_TASKและHOURLY_AGG_TASKอยู่ในสถานะstarted - กิจกรรมของ CDC — task ทั้งสองเคยทำงานเมื่อไม่นานมานี้
- การป้อนข้อมูลของ producer — producer การเดินทางกำลังแทรกข้อมูลอย่างต่อเนื่อง
- Superset — แดชบอร์ด BI เข้าถึงได้ที่
http://localhost:8088
หากคุณอยากตรวจด้วยมือมากกว่า SHOW TASKS LIKE '%TASK' IN DATABASE NYC_TAXI_DB; โดยใช้
role ACCOUNTADMIN (task เป็นของ role นั้น) จะยืนยันว่า task ทั้งสองกำลังทำงาน
สรุปปิดท้าย
คุณจะกลับมาที่สภาพแวดล้อมนี้ซ้ำ ๆ ในอีกไม่กี่โมดูลข้างหน้า และการรัน ./setup.sh เต็มรูปแบบ
กินเวลา 5-10 นาที ซึ่งคุณไม่อยากจ่ายทุกครั้งที่ปรับไฟล์ Terraform หรือโมเดล dbt setup.sh
รับแฟล็กมาเพื่อเรื่องนี้พอดี:
| แฟล็ก | ใช้เมื่อไร |
|---|---|
| (ไม่มี) | รันครั้งแรก จัดเตรียมทุกอย่างและสร้างข้อมูลสังเคราะห์ 50 ล้านแถว (~12 นาทีรวม) |
--skip-seed | โครงสร้างพื้นฐานมีอยู่แล้วและ TRIPS_RAW มีข้อมูลอยู่แล้ว ข้ามการสร้างข้อมูลสังเคราะห์ (ประหยัด ~8 นาที) |
--skip-dbt | อ็อบเจกต์ Snowflake มีอยู่แล้วแต่คุณไม่จำเป็นต้องรัน dbt transform ซ้ำ (เช่น ทดสอบการเปลี่ยนแปลงของ Terraform) |
--skip-superset | Docker ไม่ได้ทำงาน หรือคุณยังไม่ต้องการเลเยอร์ BI |
--full-refresh | บังคับให้ dbt สร้างโมเดล incremental ทั้งหมดขึ้นใหม่จากศูนย์ (เช่น หลังเปลี่ยนสคีมา) |
แฟล็กใช้ร่วมกันได้ สองชุดที่ใช้บ่อย:
# Re-run after a Terraform or SQL change — skip the ~10 min data load
./setup.sh --skip-seed
# Iterate on dbt models only — skip everything else
./setup.sh --skip-seed --skip-supersetหมายเหตุเรื่องค่าใช้จ่าย การใส่ข้อมูลตั้งต้นใช้เวลาราว 12 นาทีคิดเป็น 2 เครดิต ($6) และ
dbt build เต็มรูปแบบใช้เวลาราว 8 นาทีคิดเป็น 1.5 เครดิต ($5) เซสชันแล็บพาร์ตเนอร์ 8 ชั่วโมง
เพิ่มขึ้นอีกราว 12 เครดิต (~$36) — warehouse จะ auto-suspend เมื่อไม่มีงาน ดังนั้นค่าใช้จ่าย
จะหยุดสะสมระหว่างเซสชัน รวมต่อพาร์ตเนอร์ต่อวันราว 16 เครดิต ประมาณ $47
สถานะปลายทาง
Snowflake พร้อมใช้งาน: NYC_TAXI_DB สร้างครบแล้ว, สตรีม CDC และ task ตามกำหนดเวลา
ทั้งสองกำลังทำงาน, producer การเดินทางเขียนข้อมูลราว 60 การเดินทาง/นาทีเข้าไปใน
TRIPS_RAW และแดชบอร์ด Superset ทั้งสามตัวพร้อมใช้งานที่ http://localhost:8088
ปล่อยให้ producer ทำงานต่อไป อย่าหยุดสแตก Docker Compose และอย่ารัน
./teardown.sh — โมดูล 02 ถึง 05 พึ่งพาสภาพแวดล้อมนี้ที่ยังทำงานอยู่ และขั้นตอนตัดสวิตช์
ในโมดูล 05 วัดช่วงห่างที่แม่นยำซึ่ง producer สร้างขึ้นระหว่าง Snowflake กับ ClickHouse
ตอนย้ายระบบ การรื้อระบบตอนนี้จะทำให้ส่วนที่เหลือของเวิร์กช็อปล้มเหลวในแบบที่ยากจะสาวกลับ
มาถึงขั้นตอนนี้ การรื้อระบบอยู่ท้ายโมดูล 05 ไม่ใช่ที่นี่
00 ตั้งค่า
ติดตั้งชุดเครื่องมือ, สร้างบัญชีทดลองใช้สองคลาวด์, โคลนรีโป และสร้าง virtualenv ของ dbt ทั้งสองตัว — ทุกอย่างที่การย้ายระบบต้องมีก่อนคุณจะแตะข้อมูล
02 วางแผนและออกแบบ
โปรไฟล์เวิร์กโหลด Snowflake แล้วตัดสินใจด้านสถาปัตยกรรมที่การย้ายระบบจะดำเนินการ — การเลือกเอนจิน, sort key, การแปลงสคีมา, ระลอกการติดตั้งใช้งาน และการออกแบบโมเดล dbt