0

🗄️🧠 Read/Write Splitting: Tăng Gấp Đôi Sức Mạnh Database Nhờ Tách Luồng Đọc - Ghi - Database System Design P16

Read/Write Splitting: Tăng Gấp Đôi Sức Mạnh Database Nhờ Tách Luồng Đọc – Ghi

1. Dẫn nhập: Câu chuyện từ thực tế Production

Hệ thống vẫn đang báo xanh, CPU ổn định, log không một dòng đỏ. Nhưng ngay sau khi người dùng nhấn "Lưu" để cập nhật thông tin cá nhân hoặc xác nhận đơn hàng, trang web tải lại và... họ vẫn thấy dữ liệu cũ như chưa từng có cuộc chia ly. Họ nhấn F5 liên tục, dữ liệu mới lúc ẩn lúc hiện một cách kỳ quái.

Là một kỹ sư vận hành, cảm giác bối rối nhất không phải là khi hệ thống sập hoàn toàn, mà là khi nó "vẫn chạy" nhưng dữ liệu lại sai lệch. Ở tập trước (Episode 15), chúng ta đã bàn về cách Replication giúp hệ thống sống sót qua thảm họa và mở rộng khả năng đọc. Tuy nhiên, khi bạn bắt đầu thực sự đẩy traffic vào những bản sao đó, bạn sẽ nhận ra một sự thật nghiệt ngã: Replication không phải là một "phép màu" miễn phí. Đây chính là khởi đầu của bài toán Read/Write Splitting và sự đánh đổi khốc liệt giữa hiệu năng và tính nhất quán (consistency).

2. Niềm tin phổ biến vs. Thực tế phũ phàng

Trong giới phát triển, có một niềm tin rất phổ biến: "Chỉ cần thêm vài bản sao (Replica) và đẩy hết các câu lệnh SELECT sang đó là hệ thống sẽ nhanh gấp đôi."

Nghe có vẻ rất hợp lý. Chúng ta tận dụng tài nguyên dự phòng từ các node phụ, giảm tải trực tiếp cho node chính (Primary), giúp các thao tác ghi dữ liệu không bị nghẽn bởi hàng ngàn lượt truy vấn đọc cùng lúc.

Tuy nhiên, ở góc độ kiến trúc, Read/Write Splitting không đơn thuần là câu chuyện về throughput (lưu lượng). Nó là câu chuyện về "Lời hứa dữ liệu" (Consistency Promise) với người dùng. Khi tách luồng đọc - ghi, bạn phải chấp nhận rằng "sự thật" giờ đây không còn xuất hiện ở mọi nơi cùng một lúc.

Đây không chỉ là quyết định kỹ thuật, mà là một quyết định về sản phẩm. Một Senior Architect sẽ không tự ý tách luồng mà phải hỏi Product Manager: "Liệu người dùng có chấp nhận thấy dữ liệu cũ trong vòng 2 giây để đổi lấy tốc độ truy cập nhanh hơn không?" Nếu câu trả lời là "Không" (như trong thanh toán), kiến trúc của bạn sẽ phải phức tạp hơn rất nhiều.

3. Tại sao hệ thống cần Read/Write Splitting?

Khi hệ thống bước vào giai đoạn trưởng thành (Stage 4-5 trong hành trình tiến hóa kiến trúc), áp lực lên tầng dữ liệu bắt đầu trở nên rõ rệt. Chúng ta tách đọc ghi vì:

  • Xung đột tài nguyên (Resource Contention): Các câu truy vấn báo cáo (analytics) nặng nề hoặc tìm kiếm phức tạp bắt đầu chiếm dụng CPU/RAM, làm chậm các transaction ghi quan trọng như thanh toán hay đặt hàng.
  • Scale đọc độc lập với scale ghi: Trong hầu hết các hệ thống, lượng traffic đọc thường gấp hàng chục, hàng trăm lần traffic ghi. Read/Write Splitting cho phép chúng ta scale năng lực đọc bằng cách thêm nhiều Replica rẻ tiền mà không cần phải nâng cấp cấu hình node Primary đắt đỏ.
  • Production Reliability: Chúng ta không thể đặt toàn bộ niềm tin vào một node duy nhất. Việc tách tải giúp cô lập rủi ro; nếu một Replica bị treo vì query nặng, các transaction ghi ở Primary vẫn an toàn.

4. Phân tích căn nguyên: Replication Lag và Stale Read

Tại sao người dùng thấy dữ liệu cũ? Câu trả lời nằm ở Replication Lag.

Trong thực tế, cơ chế Replication thường là asynchronous (bất đồng bộ). Tại sao? Vì nếu ép Primary phải chờ tất cả Replica xác nhận đã ghi xong mới trả lời người dùng, hiệu năng ghi sẽ thê thảm. Chúng ta chọn tốc độ cho Primary và chấp nhận "độ trễ" cho Replica.

Dữ liệu cần thời gian để "bay" qua mạng, ghi vào log, và thực thi lại ở Replica. Khi ứng dụng đọc dữ liệu từ một bản sao chưa kịp cập nhật, hiện tượng này gọi là Stale Read. Trong môi trường Production, Replication Lag có thể chỉ vài mili giây, nhưng dưới áp lực IOPS cao hoặc mạng chập chờn, nó có thể lên tới vài giây – đủ để phá hỏng trải nghiệm người dùng.

5. Tư duy kỹ sư: Chiến lược điều hướng (Routing Strategy)

Tách luồng đọc ghi yêu cầu một "bộ não" điều hướng query. Mỗi lựa chọn đều đi kèm những "nỗi đau" vận hành riêng:

  • Application-level Routing: Code backend tự quyết định query nào đi đâu (thường qua 2 connection strings).
    • Nỗi đau: Code sẽ cực kỳ rối rắm khi hệ thống có hàng chục microservices. Mỗi service đều phải tự quản lý logic "node nào sống, node nào chết" và logic routing.
  • Proxy-level Routing (Middleware): Sử dụng các công cụ như ProxySQL, MaxScale đứng trước database.
    • Nỗi đau: Bạn vừa thêm một Single Point of Failure (SPOF). Nếu Proxy chết, toàn bộ hệ thống đọc chết theo. Proxy cũng tạo ra thêm một "bước nhảy" mạng (network hop), làm tăng độ trễ tổng thể (latency tax).

Không có giải pháp miễn phí. Architect phải chọn giữa việc "phức tạp hóa code" hoặc "gánh thêm chi phí vận hành hạ tầng".

6. Kỹ thuật xử lý "Session Consistency"

Để giải quyết vấn đề "vừa ghi xong đã đọc," một kỹ sư dày dạn kinh nghiệm sẽ áp dụng các kỹ thuật đảm bảo tính nhất quán trong phiên làm việc:

  • Read-Your-Own-Writes: Buộc các request đọc ngay sau khi ghi (trong một grace period ngắn) phải được điều hướng về Primary node. Điều này đảm bảo người dùng thấy đúng cái họ vừa tạo ra, trong khi traffic của người dùng khác vẫn được đẩy sang Replica.
  • GTID / LSN Tracking: Sử dụng chỉ số tuần tự của log (Global Transaction ID). Ứng dụng sẽ hỏi Replica: "Bạn đã đuổi kịp đến ID này chưa?". Nếu chưa, hệ thống có hai lựa chọn: Đợi (làm tăng Latency) hoặc Về Primary (làm tăng tải Primary).

Dưới lăng kính của một Senior Engineer: Chúng ta luôn phải cân đối giữa Latency (Độ trễ)Correctness (Tính đúng đắn). Đôi khi, ép người dùng chờ 500ms để thấy dữ liệu đúng còn tốt hơn là trả kết quả ngay lập tức nhưng sai lệch.

7. Đánh đổi và Những trường hợp thất bại (Trade-offs & Failure Cases)

Tiêu chí Nội dung
Lợi ích (Benefit) Tăng throughput tổng thể; Giảm tải cho Primary; Scale đọc linh hoạt.
Chi phí (Cost) Phức tạp trong vận hành Proxy; Code cần xử lý logic routing và tính nhất quán.
Rủi ro (Risk) Stale Read dẫn đến bug nghiệp vụ; Proxy trở thành điểm nghẽn hoặc điểm chết.

Những "cú sập" điển hình trong thực tế:

  • Dashboard tài chính: Khách hàng nạp tiền thành công, nhưng Dashboard (đọc từ Replica chậm 5 giây) báo số dư $0. Kết quả: Support cháy máy vì khách hàng hoang mang.
  • Logic kho hàng (Inventory): Hệ thống cho phép mua hàng vì Replica báo "còn 1 item," nhưng thực tế Primary đã ghi nhận hết hàng từ 1 giây trước. Kết quả: Bán vượt quá số lượng tồn kho (Overselling).
  • Hot Partition Death Spiral: Khi Load Balancer không nhận diện được sức tải, một câu query nặng ở một Replica làm nó chậm lại -> Lag tăng -> Hệ thống tự động đẩy thêm request sang các Replica khác để "cứu" -> Kéo sập toàn bộ dàn Replica theo hiệu ứng domino.

8. Tổng kết bài học

  • Read/Write Splitting không chỉ là công cụ tăng tốc, nó là một quyết định kiến trúc thay đổi cách hệ thống xử lý "sự thật".
  • Replication Lag là một khoản thuế bạn phải trả để đổi lấy khả năng mở rộng (Scalability); công việc của bạn là quản lý ngân sách đó.
  • Tính nhất quán là một thỏa thuận giữa Kỹ thuật và Sản phẩm. Đừng bao giờ áp dụng eventual consistency cho những tính năng yêu cầu sự chính xác tuyệt đối.
  • Database không chỉ là nơi lưu trữ, nó là nền tảng kiến trúc định nghĩa "lời hứa" của hệ thống với người dùng.

9. Mở rộng vấn đề

Khi số lượng query đã được tối ưu và tách luồng hiệu quả, một vấn đề khác sẽ xuất hiện khi traffic chạm ngưỡng cao hơn: Tại sao hàng ngàn request đồng thời lại có thể làm sập database chỉ vì thiếu kết nối, ngay cả khi CPU vẫn còn rất trống?

Mời bạn cùng tìm hiểu ở tập tiếp theo: Episode 17 - Connection Pool: Vì Sao Hàng Ngàn Request Chỉ Cần Vài Chục Connection Database?


🚀 Tiếp tục hành trình cùng TechCraft

Nếu bài viết này mang lại cho bạn một góc nhìn mới, thì đây mới chỉ là một phần trong hành trình khám phá Backend Engineering, System Design và Production Systems tại TechCraft.

Ngoài các nội dung miễn phí, TechCraft còn phát triển Dev Insider — chương trình học chuyên sâu dành cho những Developer muốn hiểu hệ thống từ bên trong, thay vì chỉ biết cách sử dụng chúng.

Hiện Dev Insider đang phát triển các series như:

  • 🔒 Backend Internals
  • 🔒 Database Internals
  • 🔒 Database World Case Studies
  • 🔒 Interview
  • ... và nhiều series mới được cập nhật mỗi tuần.

🚀 Dev Insider

https://www.patreon.com/techcraft_official/posts/vi-sao-dev-ra-161163881?collection=2220113

📘 Facebook
https://www.facebook.com/techcraft.official

🎥 YouTube
https://www.youtube.com/@techcraft.official

🎵 TikTok
https://www.tiktok.com/@techcraft.official

Không chỉ học cách build. Học cách build đúng.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí