Tất cả bài viết

Read replica lag — vì sao đọc stale ngay sau khi write

Replica async sau primary — read-your-writes, route sau mutation, và khi nào chấp nhận eventual consistency.

databasereplicationconsistencymysql

Bệnh nhân vừa đổi họ tên, API trả 200. Refresh trang profile — tên cũ vài giây. Dev bảo “cache” — nhưng đã xóa Redis. Thực ra read đi replica MySQL, write đi primary, replica chưa kịp apply binlog.

Đây là replication lag — không phải bug ngẫu nhiên, là hệ quả kiến trúc.


Vì sao replica luôn “đi sau” một nhịp

MySQL replication mặc định asynchronous: primary commit xong trả client, replica nhận binlog và apply sau. Tải cao, replica yếu hơn primary, migration nặng, long transaction trên replica — lag tăng từ vài ms lên giây.

Junior hay tưởng: “Có 2 DB thì gấp đôi an toàn và đồng bộ tức thì.” Thực tế: scale read đổi lấy eventual consistency trên read path.


Triệu chứng trong HMS

Khác cache stale (bài 88): invalidate Redis không fix replica lag.


Read-your-writes — pattern thực dụng

Sau mutation quan trọng, đọc từ primary trong cửa sổ ngắn:

@Service
@RequiredArgsConstructor
public class PatientService {

  @Transactional  // write — luôn primary khi dùng routing datasource
  public PatientResponse updateProfile(UUID id, UpdateRequest req) {
    Patient saved = patientRepository.save(apply(req));
    return mapper.toResponse(saved);
  }

  @Transactional(readOnly = true)
  public PatientResponse getProfile(UUID id) {
    return mapper.toResponse(patientRepository.findById(id).orElseThrow());
  }
}

Với routing datasource theo thread context:

// Sau write trong cùng request/session — force primary cho read tiếp theo
public PatientResponse updateAndReturn(UpdateRequest req) {
  PatientResponse updated = updateProfile(...);
  ReplicationContext.usePrimary(); // custom holder — clear sau request
  return getProfile(updated.getId());
}

Hoặc đơn giản hơn: API “get ngay sau post” trả body từ response write, không query replica.

Mobile app: sau POST /appointments, UI thêm item từ response JSON — không GET /appointments ngay lập tức nếu biết read path đi replica.


Các hướng khác (khi lag lớn hoặc critical)

Đừng hứa “real-time” trên read replica nếu chưa đo lag p99 trên prod.


Takeaway

Write primary, read replica → user có thể thấy data cũ ngay sau write. Với flow “sửa xong xem ngay”: read primary hoặc trả data từ write response. Dashboard báo cáo có thể chấp nhận lag — đặt lịch khám thì không.


Bài tiếp theo: (tiếp Phần 6 hoặc Production & Ops)