Hệ thống Dữ liệu Phân tán/Request routing — tìm đúng node giữ dữ liệu
18/38
Bài 18 / 38~11 phútPhân mảnh (partitioning)Miễn phí lượt xem

Request routing — tìm đúng node giữ dữ liệu

Chia dữ liệu ra nhiều node xong, client làm sao biết hỏi node nào cho một khoá? Ba cách route, dịch vụ coordination, và giữ mapping đúng khi partition di chuyển.

TL;DR: Chia dữ liệu ra nhiều node xong, câu hỏi cuối là định tuyến: client muốn khoá K, làm sao biết K nằm ở node nào — nhất là khi partition di chuyển lúc rebalancing? Có ba cách: (1) client tự biết mapping, gọi thẳng node đúng; (2) một routing tier (proxy) đứng trước, chuyển tiếp; (3) client gọi node bất kỳ, node đó tự chuyển tiếp. Cả ba đều cần một nguồn sự thật về mapping partition→node luôn cập nhật khi cụm co giãn — thường do dịch vụ coordination (ZooKeeper/etcd) giữ. Điểm khó không phải "route thế nào" mà "ai biết mapping mới nhất" và đồng bộ nó ra sao khi cụm co giãn.

Đây là mảnh cuối của partitioning: sau khi quyết chia thế nào (bài 1-2) và index thế nào (bài 3), phải trả lời tìm lại ở đâu. Và câu trả lời kéo thẳng vào một chủ đề lớn của track — làm sao nhiều thành phần thống nhất một thông tin (mapping) đang thay đổi.

Nhớ lại Service & kube-proxy

Bạn đã thấy Kubernetes giải đúng bài toán này ở tầng mạng: Service cho một tên ổn định, kube-proxy định tuyến tới pod đang sống dù pod đổi IP. Request routing ở đây là cùng ý tưởng cho dữ liệu: một lớp gián tiếp che việc "partition nào ở node nào" khỏi client, và tự cập nhật khi mapping đổi.

1. Analogy — gọi tổng đài, hỏi trực tiếp, hay được chuyển máy

Bạn cần gặp đúng người phụ trách hồ sơ của mình trong một toà nhà lớn, mà phòng ban hay đổi tầng:

  • Bạn tự có sơ đồ tầng mới nhất (client tự biết): đi thẳng đúng phòng. Nhanh, nhưng bạn phải luôn có bản sơ đồ cập nhật — tầng đổi mà bạn không biết là đi nhầm.
  • Có quầy lễ tân (routing tier): bạn hỏi lễ tân, họ chỉ/đưa tới đúng phòng. Bạn không cần biết sơ đồ; chỉ lễ tân cần cập nhật.
  • Hỏi bất kỳ ai gặp, họ chuyển tiếp (node tự forward): gặp ai cũng được, họ biết đường và dẫn bạn tới đúng phòng. Tiện cho bạn, nhưng mỗi nhân viên phải biết sơ đồ.

Điểm chung: dù cách nào, phải có một sơ đồ tầng đúng và ai đó giữ nó cập nhật khi phòng ban chuyển tầng. Đó mới là phần khó.

Toà nhàRequest routing
Sơ đồ tầngMapping partition → node
Tự có sơ đồ, đi thẳngClient tự biết mapping
Hỏi lễ tânRouting tier / proxy
Hỏi bất kỳ ai, được chuyểnNode bất kỳ tự forward
Phòng ban đổi tầngPartition di chuyển (rebalancing)
Ai giữ sơ đồ cập nhậtDịch vụ coordination

2. Ba cách định tuyến

Ba cach dinh tuyen khac nhau o cho dat mapping va so hop

Ba cách khác nhau ở ai giữ bản sao mappingai lo cập nhật nó khi partition di chuyển:

  • (1) Client tự biết mapping. Mỗi client giữ (hoặc cache) bảng partition→node, tự tính partition của khoá rồi gọi thẳng node đúng — ít hop nhất, chỉ một chặng mạng tới node. Cái giá: mapping bị sao thành N bản (mỗi client một bản), nên khi nó đổi phải có đường đẩy cập nhật tới mọi client; sót một nhóm client là nhóm đó ôm bản cũ, gọi nhầm node. Toàn bộ độ phức tạp "biết mapping mới nhất" dồn về phía client — bên bạn ít kiểm soát nhất.
  • (2) Routing tier (proxy). Một lớp proxy đứng trước nhận mọi request, tra mapping của riêng nó rồi chuyển tiếp tới node đúng. Client chỉ cần biết một địa chỉ (địa chỉ tier); mapping gom về một chỗ, chỉ tier phải cập nhật khi cụm co giãn. Cái giá: thêm một hop (client tới tier rồi tier tới node), và tier thành thành phần sống-còn phải scale + HA — tier chết là cả cụm mất lối vào. Thực tế chạy nhiều bản tier sau một load balancer, và các bản đó lại phải chia sẻ cùng một mapping.
  • (3) Node tự forward. Client gọi bất kỳ node; nếu node đó không giữ khoá, nó chuyển tiếp nội bộ tới node đúng rồi trả kết quả về. Client cực đơn giản (gọi ai cũng được, không cần biết mapping). Cái giá: mọi node phải biết mapping toàn cục — thường qua gossip (mỗi node định kỳ trao đổi hiểu biết "ai giữ khoảng khoá nào" với vài node lân cận, dần dần cả cụm hội tụ về cùng bức tranh) — và một request gọi lệch node phải chịu thêm một hop mạng nội bộ.
CáchMapping nằm ởAi cập nhật khi đổiSố hopĐiểm yếu chính
Client tự biếtmọi client (cache)phải đẩy tới mọi client1 (ít nhất)N bản dễ lệch nhau
Routing tiertập trung ở tierchỉ tier2 (qua proxy)tier phải HA + scale
Node tự forwardmọi node (gossip)gossip lan dần1–2 (có thể lệch)gossip hội tụ có độ trễ

Mấu chốt: cả ba chỉ dời chỗ đặt độ phức tạp (client / một tier / mọi node) và đổi số hop, chứ không xoá được câu hỏi "ai giữ mapping mới nhất" — mục sau trả lời trực tiếp câu hỏi đó.

3. Ai giữ mapping — và vì sao đó là phần khó?

Cả ba cách đều dựa trên một mapping partition→node đúng. Khi cụm ổn định, mapping tĩnh — dễ. Cái khó là lúc rebalancing: partition di chuyển, và giờ nhiều thành phần (mọi client, hoặc mọi node, hoặc routing tier) phải cùng thấy thay đổi đó, nếu không request đi tới node cũ (không còn giữ khoá) → lỗi hoặc chuyển tiếp thừa.

Đây là một bài toán thống nhất một thông tin đang thay đổi giữa nhiều node — và nó xuất hiện khắp hệ phân tán. Giải pháp phổ biến: một dịch vụ coordination chuyên trách (ZooKeeper, etcd) giữ mapping như nguồn sự thật; các thành phần đăng ký theo dõi và được thông báo khi mapping đổi. Bản thân dịch vụ đó phải nhất quán mạnh (không được cho hai câu trả lời khác nhau về "ai giữ partition P") — nên nó dùng consensus bên trong.

Nói cách khác: routing đẩy độ khó về đúng câu hỏi trung tâm của cả track — làm sao nhiều node đồng ý một sự thật — mà Module 6 (consensus) sẽ mổ. Request routing là một ứng dụng cụ thể đầu tiên của consensus mà bạn gặp.

4. Pitfall — mỗi thành phần tự đoán mapping, không có nguồn sự thật

Pitfall — cache mapping mà không có cơ chế cập nhật khi nó đổi

Cách hỏng phổ biến: client (hoặc node) cache bảng partition→node để đi thẳng cho nhanh, nhưng không có đường nhận biết khi mapping đổi.

❌ Client cache mapping luc khoi dong -> rebalancing chuyen partition P sang node moi
   -> client van goi node cu -> node cu khong con giu P -> loi / tra sai
   -> moi client cache mot phien ban khac nhau -> hanh vi loan

❌ Khong co nguon su that -> moi node tu "doan" ai giu gi -> khong dong bo

Hệ quả: sau mỗi lần co giãn, một phần request đi nhầm chỗ cho tới khi cache hết hạn — lỗi lúc-có-lúc-không, khó tái hiện.

Hướng đúng: luôn có một nguồn sự thật cho mapping (dịch vụ coordination nhất quán mạnh), và cơ chế thông báo/theo dõi để các thành phần cập nhật khi mapping đổi (watch/notify, hoặc phiên bản mapping kèm mỗi response để phát hiện cache cũ). Cache để nhanh thì được, nhưng phải có đường làm mới khi nguồn sự thật đổi — đừng để cache thành sự thật.

5. Tự thiết kế routing — đến lượt bạn

Bạn đã có ba cách route + hiểu phần khó nằm ở giữ mapping đồng bộ. Giờ tự thiết kế cho một tình huống cụ thể: đọc kỹ rồi tự quyết (a) chọn cách route nào, (b) đặt nguồn sự thật của mapping ở đâu, (c) biện minh — viết ra (trong đầu hoặc ra giấy) trước khi mở đáp án.

Kho key-value cho một game mobile. Khoảng 8 triệu client là app chạy trên điện thoại người dùng, mạng chập chờn, và bạn không kiểm soát được vòng đời chúng (không thể đẩy cập nhật tức thì tới mọi máy — người dùng cập nhật app khi nào tuỳ họ). Cụm 30 node giữ trạng thái người chơi và co giãn mạnh quanh giờ cao điểm/sự kiện — thêm/bớt node vài lần mỗi ngày, nên partition di chuyển thường xuyên. Yêu cầu: đọc/ghi độ trễ thấp, và không để client gọi nhầm node sau mỗi lần co giãn.

Tự kiểm tra
0/1 câu đã trả lời
  1. Q1
    Với kho key-value game mobile trên: chọn cách route nào trong ba cách, đặt nguồn sự thật của mapping partition→node ở đâu, và vì sao? Biện minh dựa trên đặc điểm client (8 triệu app mobile không đẩy cập nhật được) và tần suất rebalancing.

6. 📚 Deep Dive

📚 Deep Dive — Request routing
  • Designing Data-Intensive Applications (Kleppmann) — Chương 6, mục "Request Routing" — ba cách route, vai trò của dịch vụ coordination (ZooKeeper) giữ mapping và thông báo thay đổi.
  • Nhiều hệ dùng ZooKeeper/etcd làm nguồn mapping (và cả membership); một số (kiểu Cassandra) dùng gossip để mọi node cùng biết ai giữ khoảng khoá nào, cho phép cách (3) node tự forward mà không cần tier riêng.

Ghi chú: DDIA Ch6 nhấn: routing không khó ở "gửi đi đâu" mà ở "giữ mapping đồng bộ khi nó đổi" — chính là consensus.

7. Liên hệ các bài khác

8. Tóm tắt

  • Request routing: client cần khoá K, làm sao tới node giữ K — khó vì mapping partition→node đổi khi rebalancing.
  • Ba cách: client tự biết (ít hop, client phức tạp) · routing tier (client đơn giản, thêm hop) · node tự forward (client đơn giản, mọi node phải biết mapping).
  • Cả ba cần một nguồn sự thật về mapping luôn cập nhật — thường do dịch vụ coordination (ZooKeeper/etcd) giữ và thông báo thay đổi.
  • Phần khó thật sự = thống nhất mapping đang đổi giữa nhiều node → chính là consensus (Module 6).
  • Anti-pattern: cache mapping mà không có đường làm mới khi nó đổi → request đi nhầm node sau mỗi lần co giãn.

9. Tự kiểm tra

Tự kiểm tra
0/5 câu đã trả lời
  1. Q1
    Nêu ba cách request routing và điểm đánh đổi của mỗi cách (độ phức tạp đặt ở đâu, số hop).
  2. Q2
    Vì sao 'phần khó' của routing không phải cách gửi mà là giữ mapping đồng bộ? Điều gì xảy ra lúc rebalancing?
  3. Q3
    Vai trò của một dịch vụ coordination (ZooKeeper/etcd) trong routing là gì, và vì sao nó phải nhất quán mạnh?
  4. Q4
    Một hệ cache bảng mapping ở client để đi thẳng cho nhanh. Rủi ro gì khi rebalancing, và thiết kế đúng là gì?
  5. Q5
    Request routing được gọi là 'ứng dụng đầu tiên của consensus' trong track. Giải thích mối liên hệ đó.

Bài tiếp theo: Module 3 — Tổng kết & cheat sheet

Bài này đáng gửi cho bạn học cùng?

Copy link đã gắn nguồn — dán group, chat, hoặc LinkedIn.

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên

Bài tiếp theo

Module 3 — Tổng kết & cheat sheet