BigQuery 2 — Kiến trúc bên trong

15 thg 7, 2026 3 lượt xem
#architecture
#data-engineering
#distributed-systems
#bigquery
#dremel

bài tổng quan chúng ta đã thấy BigQuery là một data warehouse serverless: nạp dữ liệu, viết SQL, chạy — không có cluster để dựng, không có node để tune. Nhưng "serverless" không có nghĩa là "không có server". Bên dưới lớp vỏ đơn giản đó là một trong những hệ thống phân tán được tối ưu bậc nhất của Google, ghép từ bốn thành phần đã chạy ở quy mô petabyte nhiều năm trước khi BigQuery ra đời. Hiểu bốn thành phần này — và cách chúng phối hợp — là hiểu vì sao BigQuery quét được hàng terabyte trong vài giây, vì sao nó tính tiền theo bytes chứ không theo giờ máy, và vì sao đội của bạn không bao giờ phải "nâng cấp cluster".

Bài này xây mô hình tinh thần về kiến trúc, theo dấu một câu SQL đi xuyên qua hệ thống, rồi giải thích trụ cột thiết kế quan trọng nhất: tách rời storage và compute.

Mô hình tinh thần: bốn trụ cột

BigQuery không phải một khối phần mềm liền mạch. Nó là sự lắp ghép của bốn hệ thống Google, mỗi hệ lo một việc:

Tóm tắt vai trò từng trụ cột:

Thành phầnLoại hệ thốngVai trò trong BigQuery
DremelQuery engine phân tánBiến SQL thành cây thực thi, điều phối hàng nghìn worker (slot) chạy song song
ColossusDistributed file system (kế thừa GFS)Lưu dữ liệu bảng ở định dạng cột Capacitor, quản lý nhân bản và độ bền
JupiterMạng datacenterCung cấp băng thông petabit để compute đọc storage và để các stage shuffle dữ liệu
BorgCluster manager (tiền thân của Kubernetes)Cấp phát và giám sát các container mà Dremel chạy trên đó

Điểm mấu chốt: compute (Dremel) và storage (Colossus) là hai hệ tách rời, nối với nhau bằng Jupiter. Đây là nền tảng cho mọi tính chất "serverless" mà bạn thấy ở lớp trên. Ta sẽ quay lại trụ cột này ở cuối bài.

Dremel — engine thực thi

Dremel là trái tim của BigQuery, được mô tả lần đầu trong bài báo Dremel: Interactive Analysis of Web-Scale Datasets (Melnik và cộng sự, VLDB 2010). Ý tưởng cách mạng của Dremel là kết hợp hai thứ tưởng như đối lập: lưu trữ dạng cột cho dữ liệu lồng nhau, và mô hình thực thi kiểu cây (multi-level serving tree) vay mượn từ hệ thống search của Google.

Cây serving tree nhiều tầng

Thay vì một node điều phối duy nhất phải gom toàn bộ dữ liệu (nút thắt cổ chai), Dremel phân rã truy vấn thành một cây nhiều tầng. Câu hỏi được đẩy xuống cây, kết quả được tổng hợp lên cây:

Cách đọc cây này:

  • Root server nhận truy vấn. Nó biết bảng có bao nhiêu tablet (shard) trên Colossus, và viết lại truy vấn thành nhiều mảnh con để phát xuống.
  • Các tầng mixer (intermediate) làm nhiệm vụ tổng hợp một phần: gom kết quả từ nhiều lá, cộng dồn, rồi đẩy tiếp lên trên. Nhờ có nhiều tầng, không một node nào phải nhận toàn bộ dữ liệu.
  • Leaf slot là nơi làm việc nặng nhất: mỗi lá đọc một phần dữ liệu từ Colossus, áp filter, tính tổng hợp cục bộ (partial aggregation), rồi trả về phần kết quả nhỏ gọn.

Trong BigQuery hiện đại, đơn vị công cụ ở lá được gọi là slot — một CPU ảo cộng với bộ nhớ, là đơn vị tính toán mà BigQuery cấp phát cho truy vấn. Một câu SQL được chia thành nhiều stage, mỗi stage lại chia thành hàng trăm/nghìn đơn vị công việc chạy song song trên các slot. Chi tiết về slot và cách một câu SQL biến thành cây stage được trình bày sâu ở bài về slot và execution model.

Chìa khoá của tốc độ: vì dữ liệu ở định dạng cột, một truy vấn chỉ chạm SELECT amount FROM transactions chỉ đọc cột amount, bỏ qua hàng chục cột khác trên đĩa — đây là nền tảng của mô hình tính tiền theo bytes. Chi tiết về Capacitor và lưu trữ cột ở bài về storage cột.

Colossus — hệ thống file lưu trữ

Colossus là thế hệ kế tiếp của Google File System (GFS), là nơi mọi dữ liệu bảng của BigQuery thực sự nằm. Vài đặc điểm quan trọng:

  • Định dạng cột Capacitor. BigQuery không lưu file Parquet trần; nó dùng định dạng cột riêng tên Capacitor, tối ưu để mã hoá, nén và bỏ qua dữ liệu (data skipping) dựa trên thống kê.
  • Độ bền và nhân bản. Colossus tự lo nhân bản dữ liệu qua nhiều đĩa/máy, tự phát hiện và sửa hư hỏng, mã hoá at-rest. Người dùng BigQuery không thấy và không cần quản lý điều này.
  • Storage là "trạng thái nguồn". Dữ liệu tồn tại độc lập với bất kỳ truy vấn nào. Không có truy vấn nào chạy thì storage vẫn còn nguyên, vẫn tính tiền lưu trữ — nhưng không tốn compute.

Điểm cần khắc cốt: Dremel không sở hữu dữ liệu. Các worker của Dremel là stateless đối với dữ liệu bảng — chúng đọc từ Colossus khi cần, xử lý, rồi biến mất. Đây chính là cái làm nên tính đàn hồi.

Jupiter — mạng petabit

Trong một hệ mà storage và compute tách rời, mọi byte dữ liệu bảng đều phải đi qua mạng để tới worker. Nếu mạng chậm, kiến trúc tách rời sẽ sụp đổ vì compute cứ phải ngồi chờ dữ liệu. Google giải bài toán này bằng Jupiter — kiến trúc mạng datacenter cung cấp băng thông cỡ petabit/giây, đủ để hàng chục nghìn máy đọc storage đồng thời mà không nghẽn.

Jupiter phục vụ hai luồng lưu lượng khác nhau:

  1. Compute ↔ Storage: leaf slot đọc tablet từ Colossus.
  2. Shuffle giữa các stage: khi một stage kết thúc (ví dụ đã gom một phần theo GROUP BY), kết quả trung gian phải được phân phối lại (repartition) tới stage kế tiếp. Việc trao đổi này gọi là shuffle, đi hoàn toàn qua Jupiter (và một lớp shuffle trong bộ nhớ). Trong query plan, bạn sẽ thấy thông số shuffleOutputBytes cho mỗi stage — đó chính là lượng dữ liệu chảy qua mạng này.

Không có Jupiter, mô hình "storage rẻ ở một nơi, compute co giãn ở nơi khác" là bất khả thi.

Borg — điều phối container

Các worker Dremel không chạy trên "máy chủ BigQuery" cố định. Chúng chạy như các task trong container, được cấp phát bởi Borg — hệ điều phối cluster của Google (chính là tiền thân, và nguồn cảm hứng, của Kubernetes). Borg lo:

  • Cấp phát: khi một truy vấn cần thêm slot, Borg tìm chỗ trống trên hàng nghìn máy và khởi chạy task ở đó.
  • Chịu lỗi: nếu một worker chết giữa chừng (máy hỏng, bị thu hồi để nhường tài nguyên), Borg khởi động lại task. Vì worker là stateless đối với dữ liệu, một mảnh công việc thất bại chỉ cần chạy lại — truy vấn không hỏng toàn bộ.
  • Đóng gói: nhiều truy vấn của nhiều khách hàng cùng chạy trên chung một hạ tầng vật lý, Borg đóng gói (bin-packing) chúng để dùng máy hiệu quả.

Chính lớp Borg giải thích vì sao BigQuery serverless: bạn không thấy máy nào, vì tài nguyên được cấp và thu hồi động dưới sự điều khiển của Borg cho từng truy vấn.

Theo dấu một câu query

Hãy ráp bốn trụ cột lại bằng cách theo một câu SQL thật đi từ lúc bấm Run tới lúc trả kết quả. Giả sử phòng Rủi ro của ngân hàng chạy:

-- Tổng giá trị và số lượng giao dịch theo chi nhánh trong tháng 6/2026
SELECT
  branch_id,
  COUNT(*)         AS so_giao_dich,
  SUM(amount)      AS tong_gia_tri,
  AVG(amount)      AS gia_tri_tb
FROM `ncb-dwh.core.transactions`
WHERE txn_date BETWEEN DATE '2026-06-01' AND DATE '2026-06-30'
  AND status = 'POSTED'
GROUP BY branch_id
ORDER BY tong_gia_tri DESC;

Luồng đi qua hệ thống:

Đọc từng bước:

  1. Root nhận và lập kế hoạch. Dremel root parse SQL, kiểm tra quyền (IAM), rồi biến truy vấn thành cây stage. Nó dùng metadata bảng để ước lượng lượng bytes cần quét (đây là con số hiện lên "This query will process X" trước khi chạy).
  2. Borg cấp slot. Root xin tài nguyên; Borg cấp các container để chạy leaf và mixer.
  3. Leaf đọc Colossus qua Jupiter. Mỗi leaf chỉ đọc bốn cột liên quan từ Capacitor, không đọc các cột khác của bảng. Nhờ partition pruning (nếu bảng phân vùng theo txn_date), phần lớn dữ liệu ngoài tháng 6 còn bị bỏ qua ngay từ đầu.
  4. Lọc + gom cục bộ. Mỗi leaf áp WHERE, rồi tính partial aggregation theo branch_id trên phần dữ liệu của nó.
  5. Shuffle. Kết quả một phần được repartition theo branch_id qua Jupiter, để tất cả dữ liệu của cùng một chi nhánh về chung một chỗ ở stage sau.
  6. Gom cuối + sort. Stage kế tiếp cộng dồn ra COUNT/SUM/AVG cuối cùng và sắp xếp theo tong_gia_tri.
  7. Root trả kết quả. Kết quả tổng hợp đi ngược lên cây về root, rồi về người dùng.

Toàn bộ chuỗi này với một bảng vài trăm triệu dòng thường xong trong vài giây, vì hàng nghìn slot chạy song song ở bước 3-4. Cách đọc chi tiết cây stage này — thời gian mỗi pha, slotMs, phát hiện data skew — là nội dung của bài về execution model.

Vì sao tách rời storage và compute

Đây là quyết định kiến trúc quan trọng nhất, và là thứ phân biệt BigQuery với data warehouse kiểu cũ (nơi CPU và đĩa gắn chặt trong cùng một node). Hãy so sánh:

Khía cạnhKho dữ liệu shared-nothing cổ điểnBigQuery (tách storage/compute)
Đơn vị mở rộngThêm node = thêm cả CPU đĩa cùng lúcMở rộng compute và storage độc lập
Dữ liệu ngồi imVẫn chiếm node, vẫn tốn computeNằm trên Colossus, chỉ tốn tiền lưu trữ
Tăng đột biến tảiPhải provision sẵn cho đỉnhBorg cấp thêm slot theo nhu cầu từng truy vấn
Rủi ro data skew khi rescalePhải reshard/di chuyển dữ liệuKhông cần — compute stateless, dữ liệu không nhúc nhích

Ba hệ quả thực tế của việc tách rời:

  • Scale độc lập. Dữ liệu lịch sử 5 năm của ngân hàng có thể nằm yên trên Colossus với chi phí lưu trữ thấp, trong khi compute chỉ được huy động (và tính tiền) đúng lúc có người chạy truy vấn. Bạn không phải trả tiền cho một cluster "to phòng khi cần".
  • Đàn hồi tức thời. Một câu truy vấn nặng có thể huy động hàng nghìn slot trong vài giây rồi trả lại, vì slot không bị trói vào nơi lưu dữ liệu. Không có bước "di chuyển dữ liệu tới compute" tốn kém.
  • Không tranh chấp storage. Nhiều đội có thể đọc cùng một bảng đồng thời mà không giành giật đĩa của nhau, vì mỗi truy vấn có compute riêng đọc từ storage dùng chung. Điều này khả thi chỉ vì Jupiter đủ nhanh để mọi worker cùng đọc Colossus mà không nghẽn mạng.

Nói ngắn gọn: Colossus giữ dữ liệu bền và rẻ, Dremel mượn compute co giãn từ Borg, Jupiter nối hai bên đủ nhanh để khoảng cách vật lý trở nên vô hình. Bốn trụ cột phối hợp để tạo ra ảo giác "serverless" mà người dùng cuối cảm nhận.

Use case thực tế

Phòng Phân tích Rủi ro của NCB có bảng transactions khoảng 1,2 tỉ dòng/năm, mỗi dòng ~30 cột, tổng ~800 GB trên Colossus. Cuối mỗi quý, đội chạy một loạt truy vấn tổng hợp nặng để lập báo cáo giám sát giao dịch bất thường; ngoài giờ đó, bảng hầu như chỉ được đọc lẻ tẻ.

Với kiến trúc gắn CPU–đĩa kiểu cũ, họ sẽ phải duy trì một cluster đủ lớn để chịu đỉnh cuối quý suốt cả năm — trả tiền 90 ngày để dùng thật sự vài ngày. Với BigQuery:

  • Ngoài mùa cao điểm: chỉ trả phí lưu trữ cho ~800 GB (dữ liệu nằm im trên Colossus), gần như không có chi phí compute.
  • Cuối quý: truy vấn tổng hợp huy động hàng nghìn slot trong ít phút; nhờ chỉ đọc vài cột (amount, branch_id, status, txn_date) thay vì cả 30 cột, lượng bytes quét — thứ quyết định hoá đơn — giảm mạnh so với đọc toàn bảng.
  • Nhiều đội đọc song song: đội Rủi ro, đội Kế toán và đội BI có thể cùng truy vấn bảng này trong giờ chốt sổ mà không đội nào làm chậm đội nào, vì compute tách rời và Jupiter gánh được lưu lượng đồng thời.

Kết quả: chi phí bám sát mức sử dụng thực, và không có cuộc họp nào về "nâng cấp cluster".

Ghi nhớ

  • BigQuery lắp từ bốn hệ Google: Dremel (thực thi), Colossus (lưu trữ), Jupiter (mạng), Borg (điều phối container).
  • Dremel dùng mô hình cây serving tree nhiều tầng: root lập kế hoạch, mixer tổng hợp một phần, leaf slot làm việc nặng — không node nào phải nhận toàn bộ dữ liệu.
  • Colossus lưu dữ liệu ở định dạng cột Capacitor; worker Dremel là stateless với dữ liệu, đọc khi cần rồi biến mất.
  • Jupiter (mạng petabit) làm cho việc tách storage/compute khả thi và gánh luồng shuffle giữa các stage.
  • Borg cấp phát/thu hồi slot động và khởi động lại worker chết, tạo ra tính chất serverless.
  • Tách rời storage/compute cho phép scale độc lập, đàn hồi tức thời và không tranh chấp storage — nền tảng của mô hình tính tiền theo bytes.
  • Một query đi: root lập kế hoạch → Borg cấp slot → leaf đọc cột từ Colossus qua Jupiter → lọc + gom cục bộ → shuffle → gom cuối → trả về root.
  • Định dạng cột giúp chỉ đọc đúng cột cần, giảm bytes quét — chi tiết ở bài storage cột.

Nguồn tham khảo

  • Melnik và cộng sự, Dremel: Interactive Analysis of Web-Scale Datasets, VLDB 2010 — bài báo gốc mô tả storage cột + serving tree nhiều tầng.
  • BigQuery documentation — Tổng quan: cloud.google.com/bigquery/docs
  • BigQuery — Query plan and timeline (execution details, shuffle, stage): cloud.google.com/bigquery/docs/query-plan-explanation
  • BigQuery — Best practices, performance overview: cloud.google.com/bigquery/docs/best-practices-performance-overview
  • BigQuery — Reservations & slots (mô hình compute): cloud.google.com/bigquery/docs/reservations-intro
  • BigQuery — Pricing (storage vs compute): cloud.google.com/bigquery/pricing
  • Lakshmanan & Tigani, Google BigQuery: The Definitive Guide, O'Reilly — chương kiến trúc (Dremel, Colossus, Jupiter, Borg, Capacitor).

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ẻ!