BigQuery 4 — Slots & mô hình thực thi

15 thg 7, 2026 3 lượt xem
#data-engineering
#bigquery
#reservations
#slots
#execution-model

Vì sao phải hiểu "slot" trước khi đọc query plan

bài kiến trúc ta đã thấy BigQuery tách rời storage (Colossus) và compute (Dremel), nối nhau qua mạng Jupiter và điều phối bởi Borg. Bài này đi sâu vào lớp compute đó và trả lời hai câu hỏi mà mọi kỹ sư dùng BigQuery đều phải nắm:

  1. Một truy vấn thực sự chạy như thế nào? — nó được chia thành các stage, mỗi stage bung ra hàng trăm/nghìn worker chạy song song, dữ liệu giữa các stage đi qua shuffle.
  2. Tài nguyên compute được đo và tính tiền ra sao? — bằng đơn vị slot, và có hai mô hình mua slot rất khác nhau (on-demand vs capacity/Editions).

Nắm chắc "slot + stage + shuffle" chính là mô hình tinh thần để sau này đọc được Execution Details, đọc execution graphphân tích thông số từng pha stage. Nếu bỏ qua bước này, các con số slotMs, shuffleOutputBytes, parallelInputs sẽ chỉ là chữ vô nghĩa.

Slot là gì

Slot là đơn vị compute ảo của BigQuery — hình dung nó như "một worker CPU" gồm một phần CPU, RAM và băng thông mạng mà Dremel cấp cho công việc tính toán. Khi bạn chạy một truy vấn, BigQuery ước lượng query cần bao nhiêu slot rồi cấp phát từ một pool tài nguyên khổng lồ dùng chung.

Vài điểm cần khắc sâu ngay để tránh hiểu sai:

  • Slot không phải là một máy ảo cố định bạn thuê. Nó là đơn vị đo năng lực xử lý, được cấp và thu hồi linh động theo mili-giây. Một truy vấn có thể dùng 200 slot ở stage này rồi tụt xuống 20 slot ở stage sau, tuỳ nhu cầu.
  • Slot được chia sẻ và tái phân bổ liên tục giữa các stage của cùng một query và giữa nhiều query khác nhau. Cơ chế chia này gọi là fair scheduling (bàn ở dưới).
  • Thước đo tiêu thụ compute thực tế là slot-milliseconds (slotMs): bằng số slot nhân với thời gian chúng được dùng. Một query dùng 100 slot trong 2 giây tiêu ~200.000 slotMs. Đây là con số bạn sẽ thấy khắp query plan và trong INFORMATION_SCHEMA.JOBS (total_slot_ms).

Nói cách khác: slot đo "bao nhiêu công việc song song đang chạy tại một thời điểm", còn slotMs đo "tổng lượng công việc đã làm".

Một truy vấn được thực thi như thế nào

Khi bạn submit SQL, BigQuery không chạy nó như một khối liền mạch. Bộ tối ưu biên dịch truy vấn thành một cây các STAGE (execution tree). Mỗi stage:

  • Thực hiện một nhóm thao tác gần nhau (đọc, lọc, join, gom nhóm, sắp xếp, ghi…).
  • Được bung ra thành nhiều đơn vị công việc song song (parallelInputs) — mỗi đơn vị do một worker (một slot đang hoạt động) xử lý trên một mảnh dữ liệu.
  • Phụ thuộc vào stage khác qua trường inputStages: một stage chỉ chạy khi các stage đầu vào của nó đã sinh đủ dữ liệu.

Giữa hai stage, dữ liệu không được ghi ra bảng trung gian trên đĩa như MapReduce cổ điển. Thay vào đó nó đi qua shuffle: một lớp bộ nhớ/mạng phân tán (chạy trên Jupiter) nơi worker của stage trước ghi các mảnh dữ liệu (ví dụ chia theo khoá join/khoá group-by), rồi worker của stage sau đọc lại đúng phần nó cần. Lượng dữ liệu qua shuffle chính là shuffleOutputBytes; nếu shuffle đầy RAM và phải tràn xuống đĩa thì có shuffleOutputBytesSpilled — dấu hiệu cần chú ý.

Sơ đồ trên là một execution graph thu nhỏ. Đọc từ dưới cây lên: các stage lá đọc dữ liệu từ Colossus, các stage giữa tổng hợp dần, stage gốc ghi kết quả cuối. Đây đúng là hình dạng bạn sẽ gặp lại (đầy đủ hơn) khi mở tab Execution details trong console — xem bài đọc execution graph.

Một stage gồm những "step" gì

Bên trong mỗi stage là chuỗi các step, mỗi step có một kind thao tác. Các kind thật thường gặp:

kindÝ nghĩa
READĐọc cột từ storage hoặc từ shuffle của stage trước
FILTERÁp điều kiện WHERE
COMPUTETính biểu thức, ép kiểu, hàm vô hướng
AGGREGATEGom nhóm GROUP BY, hàm tổng hợp
JOIN / CROSS_JOINGhép hai nguồn dữ liệu
SORTSắp xếp (ORDER BY, chuẩn bị cho window)
ANALYTIC_FUNCTIONHàm cửa sổ (OVER (...))
LIMITCắt bớt số dòng
WRITEGhi ra shuffle cho stage sau, hoặc ra kết quả cuối

Một AGGREGATE hay JOIN thường bị chia làm hai stage: một stage làm partial trên từng mảnh dữ liệu cục bộ, rồi shuffle để gom các dòng cùng khoá về một chỗ, rồi stage sau làm final. Đây là lý do bạn hay thấy cặp stage kiểu "aggregate → aggregate" trong plan.

Ví dụ SQL và hình dạng plan tương ứng

Truy vấn ngân hàng đếm số giao dịch và tổng tiền theo chi nhánh trong tháng:

SELECT
  t.branch_id,
  COUNT(*)        AS so_giao_dich,
  SUM(t.amount)   AS tong_tien
FROM `ncb-dwh.core.transactions` AS t
WHERE t.txn_date BETWEEN '2026-06-01' AND '2026-06-30'
GROUP BY t.branch_id
ORDER BY tong_tien DESC;

BigQuery sẽ dựng đại khái:

  • Stage 0READ cột branch_id, amount, txn_date từ Colossus, FILTER theo txn_date, rồi AGGREGATE partial theo branch_id, WRITE ra shuffle (chia theo branch_id).
  • Stage 1READ từ shuffle, AGGREGATE final (cộng dồn các partial cùng branch_id), SORT theo tong_tien, WRITE kết quả.

Vì chỉ đọc 3 cột (nhờ lưu trữ cột Capacitor) và lọc sớm bằng WHERE, stage 0 quét ít byte → ít slot-time hơn. Đây là mối liên hệ trực tiếp giữa cách viết SQL và lượng compute tiêu thụ.

Hai mô hình compute: on-demand vs capacity (Editions)

BigQuery có hai cách hoàn toàn khác nhau để cung cấp và tính tiền slot. Hiểu sự khác biệt này quan trọng cả về chi phí lẫn hiệu năng.

On-demand

  • Bạn không phải quản lý slot. BigQuery tự động cấp phát và autoscale slot cho từng query (mỗi project có một giới hạn mềm mặc định cỡ 2000 slot dùng đồng thời).
  • Tính tiền theo số byte truy vấn xử lý (totalBytesBilled), không theo thời gian slot. Chạy nhanh hay chậm không đổi hoá đơn — chỉ số byte đọc mới quyết định tiền. Đây là lý do tối ưu chi phí on-demand = giảm byte quét (partition, cluster, chọn ít cột). Xem sâu ở bài định giá theo byte.
  • Ưu điểm: đơn giản, không cam kết, hợp tải thấp hoặc thất thường. Nhược: khó dự đoán hoá đơn khi có query "quét cả bảng", và bị trần 2000 slot nên đỉnh tải có thể chậm.

Capacity / Editions (reservations)

  • Bạn mua năng lực slot thông qua cơ chế reservations của BigQuery Editions (Standard, Enterprise, Enterprise Plus). Mô hình gồm ba khối:
    • Capacity commitment: cam kết một lượng slot (theo tháng/năm) để có giá tốt.
    • Reservation: một "hồ" slot đặt tên, có baseline (slot tối thiểu luôn có) và có thể bật autoscaling tới một trần max.
    • Assignment: gán project/folder/tổ chức vào một reservation để query của họ dùng slot ở hồ đó.
  • Tính tiền theo slot-time — bạn trả cho năng lực slot theo thời gian (slot × giờ), bất kể query quét bao nhiêu byte. Query nặng byte không làm tăng tiền, nhưng chạy lâu và chiếm nhiều slot thì có.
  • Ưu điểm: chi phí dự đoán đượccô lập workload — có thể cấp reservation riêng cho ETL, cho BI, cho ad-hoc để chúng không tranh nhau. Nhược: cần quản lý và ước lượng dung lượng.

Lưu ý: đây là hai mô hình compute. Chi phí storage tính riêng trong cả hai trường hợp (theo GB lưu trên Colossus), không dính đến slot.

Cùng một reservation, slot được chia thế nào — Fair scheduling

Điểm tinh tế nhất: trong một reservation (hoặc trong pool on-demand của project), nhiều query chạy đồng thời sẽ chia sẻ slot theo cơ chế fair scheduling. Nguyên tắc:

  • BigQuery không để một query "ngốn sạch" slot rồi các query khác chờ. Thay vào đó slot được chia công bằng giữa các query đang chạy, và tái phân bổ theo thời gian thực khi query đến/đi.
  • Nếu chỉ 1 query chạy, nó có thể mượn toàn bộ slot rảnh của reservation. Khi query thứ 2 tới, hệ thống thu bớt slot của query 1 để chia cho query 2. Slot rảnh không bao giờ bị lãng phí.
  • Trong Editions, tính năng idle slot sharing còn cho phép các reservation khác nhau mượn slot rảnh của nhau (nếu bật), tăng mức tận dụng.

Hệ quả thực tế: khi reservation của bạn đã bão hoà, thêm query mới không làm query cũ lỗi — chúng chỉ chậm lại vì mỗi query được ít slot hơn. Trong query plan bạn sẽ thấy điều này qua pha wait tăng lên (worker chờ được cấp slot) — chi tiết ở bài thông số từng pha.

Quan sát slot & stage bằng INFORMATION_SCHEMA

Bạn có thể tự đo tiêu thụ slot của các job gần đây bằng view hệ thống — chạy được ngay:

SELECT
  job_id,
  user_email,
  total_bytes_billed,
  total_slot_ms,
  -- slot trung bình ~ slot-ms / thời gian chạy thực tế
  SAFE_DIVIDE(
    total_slot_ms,
    TIMESTAMP_DIFF(end_time, start_time, MILLISECOND)
  ) AS avg_slots,
  ARRAY_LENGTH(job_stages) AS so_stage
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY)
  AND job_type = 'QUERY'
  AND state = 'DONE'
ORDER BY total_slot_ms DESC
LIMIT 20;

Đọc kết quả:

  • total_slot_ms cao = job tiêu nhiều compute (dù total_bytes_billed nhỏ, nếu query có nhiều join/sort tốn CPU).
  • avg_slots ≈ mức song song trung bình job đạt được. So với trần reservation để biết job có bị "đói slot" không.
  • so_stage = số stage trong plan; mỗi phần tử job_stages chứa parallelInputs, shuffleOutputBytes, slotMs, các pha waitMsAvg/Max… là dữ liệu để chẩn đoán và tinh chỉnh.

Use case thực tế

Đội Data của NCB chạy song song hai loại tải trên BigQuery: pipeline ELT ban đêm (làm sạch, gộp giao dịch, dựng bảng mart) và dashboard rủi ro tín dụng ban ngày cho phòng QLRR.

Ban đầu cả hai dùng chung on-demand. Vấn đề: một buổi cuối tháng, một analyst chạy nhầm query quét toàn bộ bảng transactions 18 TB không lọc partition → vừa tốn tiền theo byte (18 TB billed) vừa hút gần hết 2000 slot khiến các dashboard giật lag. Hoá đơn ngày hôm đó vọt bất thường và không ai dự đoán trước được.

Đội chuyển sang Editions Enterprise với hai reservation tách biệt:

  • rsv-etl: baseline 500 slot, autoscale tới 1500 — gán cho project pipeline, chạy chủ yếu ban đêm.
  • rsv-bi: baseline 300 slot, autoscale tới 600 — gán cho project dashboard.

Kết quả: chi phí compute trở nên dự đoán được (trả theo slot-time cam kết thay vì theo byte biến động), dashboard không còn bị pipeline giành slot nhờ cô lập reservation, và fair scheduling trong rsv-bi đảm bảo 30 người mở báo cáo cùng lúc thì mỗi query chậm đi chút ít chứ không ai bị lỗi. Query "quét nhầm 18 TB" nếu tái diễn thì chỉ làm chậm rsv-bi trong giới hạn 600 slot, không đội hoá đơn theo byte.

Ghi nhớ

  • Slot = đơn vị compute ảo (CPU-worker) BigQuery cấp linh động theo mili-giây; slotMs = tổng công việc đã làm = slot × thời gian.
  • Mỗi query được biên dịch thành cây STAGE; mỗi stage bung ra nhiều worker song song (parallelInputs), phụ thuộc nhau qua inputStages.
  • Dữ liệu giữa các stage đi qua shuffle (bộ nhớ/mạng phân tán), đo bằng shuffleOutputBytes; tràn đĩa = shuffleOutputBytesSpilled cần chú ý.
  • On-demand: BigQuery autoscale slot, tính tiền theo bytes — tối ưu = giảm byte quét.
  • Capacity/Editions: mua slot qua reservations (commitment + baseline + autoscale), tính tiền theo slot-time — cho chi phí dự đoán được và cô lập workload.
  • Fair scheduling chia slot công bằng giữa các query đang chạy; đói slot làm query chậm (pha wait tăng) chứ không lỗi.
  • Đây là nền để đọc Execution Details, execution graphthông số từng pha stage.

Nguồn tham khảo

  • BigQuery — Introduction to reservations (Editions, slots, commitments): cloud.google.com/bigquery/docs/reservations-intro
  • BigQuery — Query plan and timeline (execution details, stages, shuffle, slot): cloud.google.com/bigquery/docs/query-plan-explanation
  • BigQuery — INFORMATION_SCHEMA JOBS (total_slot_ms, job_stages): cloud.google.com/bigquery/docs/information-schema-jobs
  • BigQuery — Best practices for performance overview: cloud.google.com/bigquery/docs/best-practices-performance-overview
  • BigQuery — Pricing (on-demand vs capacity): cloud.google.com/bigquery/pricing
  • BigQuery documentation (tổng quan): cloud.google.com/bigquery/docs
  • "Dremel: Interactive Analysis of Web-Scale Datasets", Melnik et al., VLDB 2010
  • "Google BigQuery: The Definitive Guide", Lakshmanan & Tigani, O'Reilly

Bài viết liên quan

So sánh các định dạng dữ liệu (CSV, JSON, XML, Avro, Parquet, ORC) và lý do lưu theo cột nhanh hơn cho phân tích. Bài đi sâu vào row vs columnar storage, nén (Snappy/gzip/zstd), schema evolution, OLTP vs OLAP, object storage và partitioning để tối ưu chi phí lẫn tốc độ truy vấn.

13 thg 7, 2026 10

Data Engineering là ngành xây dựng và vận hành hệ thống biến dữ liệu thô thành dữ liệu sạch, tin cậy, sẵn sàng cho phân tích và AI. Bài giới thiệu vai trò Data Engineer trong vòng đời dữ liệu (nguồn → ingestion → storage → transformation → serving), phân biệt với Analyst/Scientist/ML Engineer, bức tranh hệ sinh thái công cụ và bài toán đưa dữ liệu core banking sang kho phân tích.

13 thg 7, 2026 9

Stream processing là gì, khác biệt batch vs stream (bounded/unbounded), micro-batch (Spark) vs true streaming, Apache Flink là gì và định vị so với Spark Structured Streaming và Kafka Streams. Kiến trúc runtime JobManager/TaskManager, các tầng API, triết lý streaming-first và bối cảnh phát hiện gian lận ngân hàng.

13 thg 7, 2026 8

Vì sao một máy không đủ và cần xử lý phân tán: từ MapReduce, Hadoop/HDFS đến Apache Spark in-memory. Kiến trúc driver–executor–cluster manager, các mức trừu tượng RDD/DataFrame/Dataset, cơ chế lazy evaluation với DAG, và vì sao shuffle (wide dependency) là phần tốn kém nhất. Kèm PySpark, Spark SQL và các kỹ thuật tối ưu (partition, broadcast join, cache, chống skew) cùng khi nào KHÔNG nên dùng Spark.

13 thg 7, 2026 7

Cảm nhận của bạn

Bình luận

Bạn cần để viết bình luận.

Chưa có bình luận. Hãy là người đầu tiên chia sẻ!