Redesigning Workers KV for increased availability and faster performance
Bài tóm tắt Cloudflare 2025 4. Điều chỉnh Độ khó: Nâng cao
Cloudflare · 2025 · 4. Điều chỉnh · Độ khó: Nâng cao — bài gốc
Bối cảnh
- Workers KV là kho KV toàn cầu: dữ liệu lưu ở storage theo vùng, cache khắp mạng Cloudflare; không chỉ khách hàng dùng mà còn là hạ tầng cho cấu hình, xác thực, phân phối asset của nhiều sản phẩm Cloudflare.
- Thiết kế gốc (2018), trước khi có Durable Objects và R2: dùng object storage của hai nhà cung cấp bên thứ ba, active-active. Ghi song song vào cả hai; xoá bằng tombstone rồi GC; đọc không có trong cache thì chạy đua hai bên, lấy bên nhanh hơn. Có cơ chế đồng bộ hai backend nhưng lệch dữ liệu vẫn xảy ra nhiều hơn mức consumer cần.
- Khi traffic tăng: hai nhà cung cấp khác nhau về giới hạn, kiểu lỗi, API, quy trình; IOPS vượt sức ghi vào cache cục bộ nên phải quay về cache truyền thống, lộ thêm ca bất nhất.
- Đầu 2025 họ chủ động rút về một nhà cung cấp để giảm độ phức tạp, biết là rủi ro tăng, coi là trạng thái tạm trong khi xây storage riêng.
- 12/6/2025 nhà cung cấp còn lại sập toàn cầu: tỉ lệ lớn request KV lỗi hơn hai giờ; Access hỏng mọi đăng nhập theo định danh, Gateway proxy không dùng được, WARP không kết nối, hàng chục dịch vụ khác bị ảnh hưởng.
Thay đổi chính
- Không bật lại được nhà cung cấp cũ: hạ tầng chạy hai backend đã gỡ, code đã "mục"; nhà cung cấp đó lại hay lỗi và giới hạn throughput thấp. Họ quyết định backend thứ hai phải do Cloudflare sở hữu và vận hành.
- Chọn DB thay vì object storage: yêu cầu là hàng trăm tỷ cặp KV, hàng petabyte, hàng triệu GET/giây, hàng chục nghìn PUT/DELETE/giây; kích thước trung vị 288 byte. Với object dưới 1 KB, database hiệu quả và rẻ hơn object storage. Dùng một distributed database đã chạy production (cũng là nền của R2 và Durable Objects), có sẵn chuyên môn và tự động hoá.
- Shard nhiều cụm, mỗi cụm nhân 3, nhất quán mạnh trong shard; nhiều cụm thay vì một cụm khổng lồ để thu nhỏ blast radius.
- KV Storage Proxy (KVSP): cho SGW (Storage Gateway Worker) một interface HTTP, lo kết nối nhị phân, xác thực, định tuyến shard; trải namespace qua các cụm bằng consistent hashing để tránh hotspot và noisy neighbor. Object lớn (tới 25 MiB) tự chuyển sang R2.
- Ghi đua vào hai backend, trả thành công khi bên đầu tiên xác nhận; bên lỗi được đưa vào hàng đợi đối soát nền.
Cách triển khai
- Ghi nền từ SGW sang backend mới để đo hiệu năng và lỗi dưới tải thật mà không chạm đường đọc.
- Copy dữ liệu cũ sang qua KVSP. Từ đây có thể failover tay trong vài phút: điểm hỏng đơn đã được gỡ.
- Bật active-active cho namespace nội bộ trước, tăng rất chậm, so sánh kết quả hai backend sau khi đã trả response cho user nên không thêm latency.
- Phát hiện hồi quy read-your-own-write trong cùng PoP (không có trong tài liệu nhưng khách đã dựa vào), rollback tạm. Dựng framework test đối kháng (đọc ghi xen kẽ dày trên vài key từ nhiều nơi) để đo tỉ lệ vi phạm, thiết kế lại cách điền và invalidate cache rồi mới bật lại.
Giữ nhất quán giữa hai backend
- Ba lớp: (1) ghi lỗi một bên thì đưa vào đối soát; (2) đọc thấy hai bên khác nhau thì kích hoạt đồng bộ; (3) crawler nền quét liên tục, đồng thời đo tốc độ trôi lệch.
- Mỗi giá trị mang version = timestamp độ phân giải cao + nonce; bản mới hơn được chép sang bên cũ bằng ghi có điều kiện (chỉ ghi nếu timestamp hiện tại cũ hơn). Xoá là ghi tombstone có timestamp mới; chỉ xoá thật khi cả hai bên đã có tombstone.
- Theo Cloudflare, KV chọn PA/EL theo PACELC. Hai cải tiến so với trước: KVSP lỗi ít hơn nhiều; mọi lần đọc đều đua cả hai bên. Thiết kế cũ sau một thời gian chỉ đọc bên nhanh hơn để tiết kiệm, tạo điểm mù: lệch có thể tồn tại mãi.
Kết quả (theo Cloudflare, 2025)
p99 latency nội bộ khi đọc qua KVSP dưới 5 ms, so với khoảng 80 ms p50 và 200 ms p99 khi đọc object store bên thứ ba (đã chuẩn hoá thời gian truyền). Mục tiêu tiếp theo: bỏ hẳn phụ thuộc bên thứ ba.
Bài học cho SWE
- Rút dự phòng để giảm phức tạp là đặt cược; nó có thể mất trong vài tháng (Độ tin cậy và multi-region, Sự cố và postmortem).
- Đường dự phòng không được dùng sẽ mục: hạ tầng gỡ đi, code cũ không bật lại được.
- Kích thước object quyết định loại kho: hàng tỷ giá trị vài trăm byte hợp database hơn object storage (Chọn database theo workload).
- Chuyển backend: ghi nền → copy → có failover tay → active-active từng nhóm namespace nội bộ trước, so sánh bất đồng bộ (Migration không downtime).
- Hành vi không được tài liệu hoá (read-your-own-write) vẫn là hợp đồng nếu khách đã dựa vào; cần test đối kháng để đo.
- Tối ưu chi phí bằng cách chỉ đọc một bên có thể làm mất khả năng phát hiện lệch.
Liên quan
Failover, replica và dự phòng dữ liệuMigration không downtimeChọn database theo workloadSự cố và postmortem
Được nhắc tới trong
Chủ đề (4)
Công ty (1)
Bài tóm tắt (3)