How we seamlessly migrated high volume real-time streaming traffic with zero data loss and duplication
Bài tóm tắt Grab 2024 3. Quy mô lớn Độ khó: Trung bình
Grab · 2024 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc
Bối cảnh
- Grab tách phần đọc và phần ghi của một backend service thành hai service riêng để scale độc lập.
- Bài kể việc chuyển phần xử lý stream (ghi) sang service mới: trung bình 20.000 lượt đọc/giây từ 16 Kafka stream, ghi ra các stream khác và nhiều bảng DynamoDB.
- Yêu cầu: chuyển từng stream một; kiểm chứng service mới trên production trước khi chuyển hẳn; không mất, không trùng dữ liệu, không downtime.
Thay đổi chính
- Loại feature flag (đã có nền tảng config/experiment): trong vài phút deploy, flag có thể được cập nhật ở hai service vào hai thời điểm hơi lệch nhau, nên có cửa sổ mất hoặc trùng dữ liệu.
- Chọn chuyển theo mốc thời gian, viết trong code dùng chung:
- Chuyển code xử lý stream vào thư mục
/commonscủa monorepo; cả service cũ lẫn mới import cùng một code, có logic bật/tắt theo service. - Tạo tài nguyên "sink" tạm (stream, bảng DynamoDB) để service mới ghi vào và được kiểm chứng trên production mà không đụng tài nguyên chính.
- Một map
stream → thời điểm chuyểnnằm trong code chung. Đến giờ đó, service mới bắt đầu ghi vào tài nguyên chính và service cũ dừng ghi, không chồng lấn, không có khoảng trống. - Deploy cả hai service trước mốc giờ một khoảng an toàn; có monitor riêng cho migration. Service cũ vẫn đọc stream thêm một thời gian nhưng không ghi, rồi mới gỡ hẳn.
- Chuyển code xử lý stream vào thư mục
Kết quả
Không mất, không trùng dữ liệu, không downtime. Toàn bộ, kể cả chuyển dần từng stream, mất khoảng 3 tuần.
Vì sao
Theo Grab: cách chuyển theo mốc thời gian đảm bảo hai bên đổi trạng thái cùng lúc, điều mà flag cập nhật lệch nhau không làm được.
Bài học cho SWE
- Hạn chế Grab tự nêu: nếu phải rollback một trong hai service thì không tránh được sai lệch dữ liệu. Logic theo thời gian nguy hiểm khi hai hệ thống lệch nhau; họ chỉ dùng vì đây là biện pháp tạm và đã test kỹ.
- Kiểm chứng bằng "sink" tạm là biến thể của shadow traffic cho luồng ghi, giống ý tưởng mock DAO năm 2016 (Grab 2016).
- Monorepo + code dùng chung làm cho hai service hành xử giống hệt nhau tại thời điểm chuyển.
Liên quan
Được nhắc tới trong
Chủ đề (4)
Công ty (1)