TL;DR

Trong database phân tán kiểu leaderless (Dynamo, Cassandra, DynamoDB, Riak, ScyllaDB), các replica có thể lệch nhau bất kỳ lúc nào do mạng chập chờn hoặc node down. Hệ thống có hai điểm thời gian để tự sửa: lúc ghi bằng hinted-handofflúc đọc bằng read-repair. Cả hai đều best-effort — chỉ có anti-entropy repair (Merkle tree) mới thực sự đảm bảo hội tụ.

Bài toán: replica divergence

Khi bạn chạy một bảng với replication factor 3, mỗi row được copy lên 3 node. Nếu node B offline đúng lúc coordinator ghi một mutation, B sẽ bị miss write đó. Đến khi B sống lại, nó đang cầm dữ liệu cũ hơn A và C. Nếu client lỡ đọc đúng node B trước khi có gì sửa nó — client nhận dữ liệu stale.

Dynamo-style database không muốn chặn write chỉ vì một replica chết (đó là lý do chọn AP thay vì CP trong tam giác CAP). Vậy câu hỏi là: sửa replica lệch ở đâu, bao giờ, và bằng cách nào?

Hai điểm sửa lỗi

Có hai thời điểm tự nhiên để phát hiện và sửa divergence:

  • Khi ghi — coordinator biết có replica không nhận được mutation, ghi chú lại để replay sau. Đây là hinted-handoff.
  • Khi đọc — coordinator so sánh phản hồi từ nhiều replica, phát hiện mismatch, push bản mới nhất lên node stale. Đây là read-repair.

Cộng lại, hệ thống sửa trên cả write path và read path, không cần quét toàn bộ dataset liên tục.

Hinted-Handoff hoạt động thế nào

Khi coordinator gửi mutation tới 3 replica và một trong số đó không phản hồi:

  1. Coordinator ghi một hint lên ổ đĩa local. Hint chứa: ID replica đích, serialized mutation (blob), timestamp gốc, và Cassandra version.
  2. Write thành công với các replica còn sống (tuỳ consistency level).
  3. Coordinator gossip để biết khi nào replica kia sống lại.
  4. Khi replica trở lại, coordinator stream hints theo từng segment; replica replay local. Segment nào replay xong thì xoá.

Hint áp dụng idempotent — timestamp gốc được giữ, nên replay không thể ghi đè một mutation mới hơn đã tới bằng đường khác.

Số quan trọng: default max_hint_window = 3 giờ trong Cassandra. Node nào offline quá 3 giờ thì coordinator ngừng tích hint — vì lưu vô hạn là vô lý, và đằng nào cũng cần full repair.

Read-Repair hoạt động thế nào

Khi client đọc với consistency level yêu cầu từ 2 replica trở lên:

  1. Coordinator gửi request tới replica, thường gồm 1 full-data read và N-1 digest reads (digest = hash nhanh của row).
  2. Nếu các digest khớp nhau → trả lời client ngay.
  3. Nếu mismatch → coordinator lấy full data từ tất cả replica, xác định bản mới nhất theo timestamp, và push update về các replica stale.

Read-repair có hai chế độ:

  • Foreground (blocking): coordinator đợi các replica stale ack update rồi mới trả client → tăng latency nhưng đảm bảo lần đọc tiếp theo chắc chắn nhất quán.
  • Background (non-blocking): trả client ngay, repair chạy async → latency đẹp, nhưng có race window ngắn.

So sánh ba cơ chế

Cơ chếKhi nào chạyPathGuaranteeChi phí
Hinted-handoffWrite (replica down)WriteBest-effort, ≤ 3hRẻ, bounded
Read-repairLúc đọcReadBest-effort, chỉ key được đọcThêm latency khi mismatch
Anti-entropy repairĐịnh kỳ / nodetool repairBackgroundGuaranteed hội tụĐắt, quét full data

Điểm chí mạng: read-repair chỉ sửa key được đọc. Cold data (dữ liệu không ai động tới) có thể thối âm thầm cho tới khi anti-entropy quét tới. Và hints chỉ giúp nếu node quay lại trong window — vượt quá thì coi như chưa có gì.

Điểm khác Cassandra vs DynamoDB

Hai database cùng họ Dynamo nhưng khác nhau ở cách tính quorum có bao gồm hint hay không:

  • Cassandrastrict quorum: hinted writes không được tính vào write consistency (trừ CL=ANY). Nếu đủ replica không sống thật, write fail.
  • DynamoDBsloppy quorum: hinted writes được tính. Đổi lại write availability 100%, nhưng read có thể stale trong khoảng thời gian hint chưa replay.

Đây là ví dụ điển hình của tradeoff CAP: cùng cơ chế, hai cách chọn, hai hành vi khác nhau.

Use cases thực tế

  • Time-series / IoT telemetry — hinted-handoff cho phép ghi liên tục kể cả khi đang rolling restart cluster.
  • Social feed, catalog đọc nhiều — read-repair opportunistic heal hot path mà không cần chạy repair thủ công.
  • Multi-region deployments (DynamoDB Global Tables, Cassandra multi-DC) — hai cơ chế này cover các partition mạng tạm thời giữa các DC.
  • Ops đơn giản hơn — node blip vài phút không cần rebuild; hint tự chạy lại.

Giới hạn & lưu ý

  • Hint window 3h là cứng. Node down lâu hơn → phải nodetool repair tay.
  • Hint có thể biến mất nếu chính coordinator crash trước khi replay (phantom consistency).
  • Read-repair bỏ quên cold data — phải chạy anti-entropy định kỳ (tuần / tháng tuỳ cluster).
  • Blocking read-repair = 2× round trip khi mismatch — tail latency xấu.
  • Không có cơ chế nào trong ba cơ chế này thay thế được nodetool repair / incremental repair. Đừng tin mỗi hint + read-repair là xong.

Kết & định hướng

Hinted-handoff và read-repair không phải là magic — chúng là hai best-effort optimization giúp giảm thời gian replica ở trạng thái lệch, chứ không đảm bảo hội tụ. Cái thật sự đảm bảo là anti-entropy repair qua Merkle tree, chạy định kỳ. Trend hiện tại (Cassandra 4.x+, ScyllaDB) là incremental repair — chỉ đối chiếu phần dữ liệu chưa từng được repair — để giảm cost của full repair, kết hợp với Paxos-based lightweight transactions cho workload cần stronger-than-eventual.

Lần tới khi bạn thấy một write thành công trên cluster đang có node chập chờn — có thể đó là hint đang âm thầm gánh. Lần tới khi một query lạ nhiên đột nhiên về đúng — có thể read-repair vừa kịp sửa giúp bạn.

Nguồn: Apache Cassandra — Hints, Cassandra Dynamo architecture, Dynamo vs Cassandra, InfluxData — Anti-Entropy, @BenjDicken.