Snowflake MigrationClickHouse Workshops

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

สภาพแวดล้อมต้นทาง Snowflake: ตัวสร้างข้อมูลสังเคราะห์แบบครั้งเดียวและ producer การเดินทางบน Docker ที่ทำงานต่อเนื่อง แทรกข้อมูลเข้า NYC_TAXI_DB ซึ่งแดชบอร์ด Superset สามตัวอ่านผ่าน analytics warehouse

รูปทรงแบบ 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_RAW
  • CDC_CONSUME_TASK — อ่านสตรีมนั้นทุก 5 นาที (รันใน RAW และถูกสั่ง resume ระหว่างการตั้งค่า) — และ HOURLY_AGG_TASK ที่รีเฟรชค่ารวมรายชั่วโมงทุกชั่วโมง (รันใน STAGING และถูกสั่ง resume หลัง dbt build)

ภายใน NYC_TAXI_DB: TRIPS_RAW ที่มีคอลัมน์ metadata แบบ VARIANT ป้อนข้อมูลให้สตรีม CDC และ task consume ตามกำหนดเวลา ขณะที่ dbt สร้าง staging view แล้วจึงสร้างตาราง fact, มิติ และค่ารวมรายชั่วโมง

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 โหลดตัวแปรสภาพแวดล้อมจากไดเรกทอรีแม่

แหล่งข้อมูลของแดชบอร์ด Superset: แดชบอร์ดปฏิบัติการสามตัวอ่านสคีมา analytics ผ่าน analytics warehouse

แดชบอร์ดสามตัวคือ 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:

คิวรีโครงสร้างที่ใช้โจทย์การย้ายระบบ
Q1DATE_TRUNC, DATEADDต่างกันเล็กน้อยที่ syntax
Q2Window ROWS BETWEENเกือบเหมือนกันใน ClickHouse
Q3QUALIFYรองรับในตัวใน ClickHouse ตั้งแต่ v24.5 — ที่นี่ยังเขียนใหม่เป็น subquery เพื่อความพอร์ตได้
Q4LATERAL FLATTENไม่มีสิ่งเทียบเท่า — ใช้ JSONExtract หรือแผ่ข้อมูลออกล่วงหน้า
Q5เส้นทางแบบโคลอนของ VARIANTแทนที่ด้วย JSONExtractFloat/JSONExtractString
Q6MERGE INTOไม่มีสิ่งเทียบเท่า — ใช้ ReplacingMergeTree
Q7Snowflake 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

สิ่งนี้ตรวจสอบ:

  1. ฐานข้อมูลและสคีมา — NYC_TAXI_DB มีอยู่ พร้อม RAW, STAGING, ANALYTICS
  2. ตารางและข้อมูล — TRIPS_RAW มีราว 50 ล้านแถว, FACT_TRIPS มีข้อมูล, ตารางมิติ มีอยู่
  3. สตรีม CDC — TRIPS_CDC_STREAM มีอยู่บน TRIPS_RAW
  4. task ตามกำหนดเวลา — CDC_CONSUME_TASK และ HOURLY_AGG_TASK อยู่ในสถานะ started
  5. กิจกรรมของ CDC — task ทั้งสองเคยทำงานเมื่อไม่นานมานี้
  6. การป้อนข้อมูลของ producer — producer การเดินทางกำลังแทรกข้อมูลอย่างต่อเนื่อง
  7. 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-supersetDocker ไม่ได้ทำงาน หรือคุณยังไม่ต้องการเลเยอร์ 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 ไม่ใช่ที่นี่

ในหน้านี้

Track your progress?

Optional. We email a link to confirm your address; progress records once you open it.

Please use your work email address, not a personal one.

Progress tracking also requires accepting the current Terms of Service in Privacy settings.

TH