Leaders, Followers & Replication Lag — Cơ chế replication (DDIA)

Phong

Mở đầu

Ảnh: panumas nikhomkhai — Pexels

Replication là một trong những chủ đề trung tâm của distributed systems. Khi bạn có dữ liệu trên nhiều node (vì lý do availability, scalability, hay latency), bạn cần một cơ chế để đảm bảo tất cả các bản sao đều có cùng dữ liệu. Chương 5 của DDIA bắt đầu bằng hình thức replication phổ biến nhất: single-leader replication (còn gọi là master-slave hay primary-secondary replication).

Đây là mô hình mà hầu hết database quan hệ (PostgreSQL, MySQL, SQL Server) đều hỗ trợ, và cũng là cách nhiều hệ thống distributed message queue, caching, và coordination service hoạt động. Hiểu rõ nó là bước đầu tiên để design một distributed system đáng tin cậy.

Leaders & Followers — Mô hình cơ bản

Ảnh: Jan van der Wolf — Pexels

Trong mô hình leader-based replication, mỗi replica (bản sao dữ liệu) có một vai trò khác nhau:

  • Leader (master/primary): Nhận tất cả các write request. Khi client ghi dữ liệu, nó phải ghi vào leader trước.
  • Followers (slaves/secondaries): Sao chép dữ liệu từ leader. Followers chỉ phục vụ read request, không nhận write trực tiếp.

Khi leader có dữ liệu mới, nó gửi replication log (hoặc change stream) đến tất cả followers. Mỗi follower nhận log và áp dụng thay đổi theo đúng thứ tự — đảm bảo tất cả replicas có dữ liệu giống hệt nhau (eventual consistency).

Mô hình này có mặt trong hầu hết database phổ biến: PostgreSQL dùng streaming replication với WAL (Write-Ahead Log), MySQL có binlog replication, MongoDB dùng primary-secondary với oplog, Kafka dùng leader-follower cho mỗi partition.

Synchronous vs Asynchronous Replication

Một quyết định quan trọng trong leader-based replication là: leader có nên đợi follower xác nhận đã nhận được dữ liệu hay không?

  • Synchronous replication: Leader đợi follower xác nhận write thành công trước khi báo cho client là write đã hoàn tất. Điều này đảm bảo dữ liệu an toàn — nếu leader chết, follower vẫn có dữ liệu. Nhưng nếu follower chậm hoặc bị lỗi, leader cũng bị block.
  • Asynchronous replication: Leader gửi dữ liệu đến follower nhưng không đợi. Nếu leader chết trước khi follower kịp sao chép, dữ liệu đó sẽ mất vĩnh viễn. Nhưng leader luôn nhanh vì không phải chờ ai.

Trong thực tế, hầu hết hệ thống dùng semi-synchronous replication: một follower được chọn làm synchronous, các follower còn lại là asynchronous. Nếu follower đó chậm hoặc chết, leader sẽ chọn một follower khác làm synchronous. Đây là cách mà PostgreSQL và MySQL thường được cấu hình để cân bằng giữa durability và performance.

Handling Node Outages

Trong distributed systems, node luôn có thể chết bất cứ lúc nào. Mô hình leader-based replication xử lý hai loại failure chính:

Follower failure: Mỗi follower duy trì một log các thay đổi đã nhận từ leader. Khi follower crash và restart, nó biết processed đến đâu trong log. Nó gửi yêu cầu đến leader để lấy tất cả thay đổi từ vị trí đó đến hiện tại — gọi là catch-up recovery. Quá trình này đơn giản và nhanh vì follower biết chính xác mình đã mất gì.

Leader failure (failover): Khi leader chết, một follower cần được promote lên làm leader mới. Quá trình này gồm 3 bước:

  1. Xác định leader đã chết (timeout — thường 30-60 giây)
  2. Chọn một follower làm leader mới (thường là follower với dữ liệu cập nhật nhất)
  3. Reconfigure hệ thống để tất cả clients biết leader mới

Failover luôn tiềm ẩn rủi ro. Nếu asynchronous replication được dùng, leader mới có thể thiếu dữ liệu so với leader cũ. Khi leader cũ quay lại, nó có thể nhận mình là leader (split brain), dẫn đến conflict dữ liệu. Hoặc nếu dùng quyết định "majority vote", hệ thống có thể đánh rơi dữ liệu từ leader cũ đã commit — gọi là quyết định đánh đổi giữa availability và durability.

Replication Lag — Vấn đề khi dùng async replication

Ảnh: Tác giả — Pexels

Hầu hết hệ thống production dùng asynchronous replication vì lý do performance. Nhưng điều này đồng nghĩa với replication lag — độ trễ giữa khi dữ liệu được ghi vào leader và khi nó xuất hiện trên follower. Khi follower bị quá tải, network chậm, hay leader có quá nhiều writes, replication lag có thể lên đến vài giây hoặc thậm chí vài phút.

Replication lag gây ra những vấn đề thú vị (và nguy hiểm) cho ứng dụng:

Read-After-Write Consistency (Đọc được ghi của mình)

Người dùng vừa submit một form (POST lên leader), sau đó refresh trang. Nếu request refresh rơi vào follower chưa kịp nhận bản sao, người dùng sẽ thấy dữ liệu cũ — như thể form chưa được submit. Rất khó chịu.

Giải pháp: Đọc dữ liệu người dùng có thể chỉnh sửa từ leader. Hoặc theo dõi thời gian của lần write gần nhất và chỉ đọc từ follower đã catch-up đến thời điểm đó. Hoặc dùng monotonic reads (bên dưới).

Monotonic Reads

Người dùng thấy dữ liệu nhảy cóc theo thời gian. Ví dụ: họ xem comment trên follower A (đã cập nhật), refresh và request rơi vào follower B (chưa cập nhật) — comment vừa thấy biến mất. Đây là hiện tượng "time travel" rất khó debug.

Giải pháp: Đảm bảo mỗi user luôn đọc từ cùng một replica (dùng consistent hashing hoặc session affinity). Hoặc đánh dấu mỗi bản ghi với timestamp và follower chỉ serve dữ liệu khi đã catch-up đến timestamp đó.

Consistent Prefix Reads

Một loại anomaly khác xảy ra khi dữ liệu có quan hệ nhân quả (causal dependency). Ví dụ: một conversation có message A (hỏi) và message B (trả lời). Nếu follower nhận B trước A (do network delay hoặc ordering khác nhau), người dùng sẽ thấy câu trả lời trước cả câu hỏi.

Giải pháp: Đảm bảo các writes có quan hệ nhân quả được ghi vào cùng một partition. Hoặc dùng vector clocks hoặc algorithms như Lamport timestamps để giữ đúng thứ tự.

Key Takeaways

  • Leader-based replication là mô hình phổ biến nhất: leader nhận writes, followers phục vụ reads và sao chép dữ liệu từ leader
  • Synchronous replication an toàn hơn nhưng chậm hơn — semi-synchronous là trade-off phổ biến
  • Failover luôn là thao tác nguy hiểm — có thể gây mất dữ liệu hoặc split-brain nếu không cẩn thận
  • Replication lag gây ra 3 vấn đề chính: read-after-write inconsistency, monotonic reads violation, và consistent prefix reads violation
  • Mỗi vấn đề đều có giải pháp riêng — thường là đánh đổi giữa consistency, performance, và complexity

Kết

Single-leader replication là nền tảng của hầu hết database và distributed systems hiện nay. Nó đơn giản, dễ hiểu, và đã được kiểm chứng qua hàng thập kỷ. Nhưng nó cũng đặt ra những câu hỏi khó về sự đánh đổi giữa consistency, availability, và performance — đặc biệt khi replication lag xuất hiện.

Trong phần tiếp theo của chương 5, DDIA sẽ đi sâu vào các vấn đề của replication lag và cách xử lý conflict trong multi-leader và leaderless replication. Nếu bạn đang build hoặc maintain một hệ thống distributed, đây là kiến thức không thể bỏ qua.