Cache made consistent: Meta's cache invalidation solution

Bài tóm tắt Meta 2022 3. Quy mô lớn Độ khó: Khó

Meta · 2022 · 3. Quy mô lớn · Độ khó: Khó — bài gốc

Bài ngoài sheet; là nguồn gốc của phần "cache invalidation và consistency API" mà Meta 2025 chỉ nhắc lướt.

Bối cảnh

  • Meta vận hành TAO (hơn một nghìn nghìn tỉ query mỗi ngày) và Memcache. Cache động khác DB ở chỗ dữ liệu bị thay đổi trên cả hai đường: đọc (cache fill) và ghi (invalidation). Ví dụ kinh điển: fill đọc được x=42, trong lúc đó x đổi thành 43 và invalidation tới trước, rồi phản hồi fill tới sau ghi đè thành 42 mãi mãi. Gắn version giải được phần lớn, nhưng entry mang version mới có thể bị evict trước khi bản cũ tới, và cache mất luôn thông tin để phân xử.
  • Theo Meta, cache bất nhất có khi tệ ngang mất dữ liệu: một hệ nhắn tin lưu "user đang ở kho nào" trong TAO; sau khi dời kho của một user, một replica TAO bất nhất làm hai người gửi tin vào hai region khác nhau, không kho nào có đủ tin nhắn (split-brain).
  • Không thể log mọi thay đổi trạng thái cache: với tỉ lệ trúng 99%, TAO vẫn có hơn 10 nghìn tỉ lần fill mỗi ngày; log hết thì biến một workload nặng đọc thành nặng ghi cho hệ log.

Thay đổi chính

  • Đo trước (Polaris): một service riêng đóng vai client, chỉ đo vi phạm bất biến mà client quan sát được, ví dụ "cache cuối cùng phải khớp DB". Nó nhận sự kiện invalidation như một cache server, rồi hỏi mọi replica cache. Yêu cầu: không báo nhầm (báo nhầm thì người ta sẽ phớt lờ). Cách làm: kiểm tra theo nhiều thang thời gian, chỉ truy vấn bỏ qua cache xuống DB (đắt, nguy hiểm cho DB) khi một mẫu bất nhất đã tồn tại qua thang báo cáo (1 hoặc 5 phút); thêm cờ trong truy vấn để biết cache server đã xử lý invalidation chưa, tách bất nhất tạm thời (do trễ) khỏi bất nhất vĩnh viễn. Chỉ số có dạng "N số 9 lần ghi vào cache nhất quán trong M phút".
  • Consistency tracing: thay vì log mọi thứ, chỉ log và trace thay đổi của cache trong cửa sổ ngắn sau mỗi lần ghi, nơi invalidation và fill có thể đua nhau; thư viện giữ chỉ mục các key vừa đổi để quyết định có log hay không, theo dõi cả eviction, và thiếu log cũng là tín hiệu (invalidation không bao giờ tới). Nhúng vào vài hệ cache lớn và dọc pipeline invalidation.
  • Một lỗi thật (2022): fill đan xen với một giao dịch hiếm cập nhật cả bảng metadata và bảng version, nên cache có metadata cũ với version mới; invalidation sau đó gặp lỗi tạm thời, nhánh xử lý lỗi gọi drop_cache(key, version) chỉ xoá nếu version trong cache nhỏ hơn, nên không xoá gì và dữ liệu cũ nằm mãi. Polaris báo ngay, tracing giúp on-call tìm ra gốc trong dưới 30 phút (trước đây có thể mất vài tuần, nếu tìm được).

Kết quả (theo Meta)

  • Độ nhất quán của TAO theo thước đo này tăng từ 99,9999% lên 99,99999999% ở thang 5 phút: dưới 1 trên 10 tỉ lần ghi còn bất nhất sau 5 phút.

Còn lại

  • Consistency cho secondary index tách rời, đo consistency lúc đọc, và một consistency API cấp cao cho hệ phân tán (giống std::memory_order nhưng cho hệ phân tán). Bài không nêu chi tiết API.

Bài học cho SWE

  • Không đo được độ nhất quán thì không cải thiện được; đo từ góc nhìn client, và chống báo nhầm trước khi tối ưu độ nhạy.
  • Lỗi cache hiếm thường nằm ở nhánh xử lý lỗi kết hợp với các thao tác đan xen.
  • Log có chọn lọc theo cửa sổ rủi ro (ngay sau ghi) rẻ hơn hàng bậc so với log hết, mà vẫn bắt được phần lớn lỗi.

Liên quan