How we migrated the database behind every Vercel build
Bài tóm tắt Vercel 2026 4. Điều chỉnh Độ khó: Nâng cao
Vercel · 2026 · 4. Điều chỉnh · Độ khó: Nâng cao — bài gốc
Bối cảnh
- Mỗi build của Vercel khởi đầu từ build warm pool (container chờ sẵn). Pool giữ trạng thái: container nào sẵn sàng, token xác thực của từng container, và ánh xạ build đang chạy → deployment bị tính tiền. Ban đầu tất cả nằm trong Redis như cache tạm.
- Theo bài, token và trạng thái dựng lại được (mất token thì pool dựng lại trong khoảng 10 phút), nhưng mất ánh xạ thì build không bao giờ được tính tiền. Họ chuyển sang DynamoDB (scale theo yêu cầu, TTL native), chấp nhận latency cao hơn Redis. Pool không bao giờ dừng nên phải chuyển trực tiếp, từng pha sau flag, có đường lùi.
Thay đổi chính
- Schema từ access pattern: liệt kê mọi việc mã đã hỏi trạng thái rồi thiết kế lại quanh container (ID là sort key, token lưu dạng hash), thay vì sao chép cấu trúc Redis; ba sorted set theo trạng thái thành một trường status, đếm qua một index nhận biết thời gian, ánh xạ billing có bảng riêng và đọc nhất quán.
- Các pha sau flag: Redis-only → dual write (Redis vẫn là nguồn sự thật) → shadow read (so khớp) → DynamoDB primary → DynamoDB-only. Dashboard theo dõi tỉ lệ khớp, lỗi ghi và latency từng truy vấn; mỗi lệch được truy ra lỗi thật, race hay khác biệt chấp nhận được trước khi sang pha sau.
- Trên đường: một lần chính tải so sánh hai kho làm build ở một region chết (thiếu index đếm, mỗi lần đếm O(n)), và hạ tầng Redis sập thật cuối tháng 3 khi pool vẫn sống nhờ đã đọc DynamoDB.
- Supply loop đình trệ (tháng 4): vòng nạp lại từng pool kiểm trạng thái trước mỗi container được tạo. Ở P95,
getWarmPoolTokenCountlà 1,29 ms trên Redis và 5,13 ms trên DynamoDB (khoảng cách rộng nhất ở P90, khoảng 17 lần); hàng trăm lần kiểm mỗi vòng kéo vòng tới hàng phút. Đó là một N+1 mà Redis đã che giấu, vì pool đứng trước nhu cầu chứ không nằm trên đường request. - Sửa: gom batch (kiểm một lần cho 17 container) bị bỏ vì hằng số 17 mã hoá tỉ lệ latency sẽ trôi theo tải. Bản chạy: các lời gọi cung cấp cho từng pool chạy đồng thời, mỗi lời gọi dùng trạng thái đã thấy gần nhất; chấp nhận tạo thừa vài container khi trạng thái hơi cũ.
Vì sao
- Bài kết luận: sao chép dữ liệu là phần dễ; việc chính là tìm các giả định đã dựa trên kho cũ. Latency truy vấn tăng từ 1 ms lên 15 ms ở P90 cũng đủ làm sập logic quản lý pool mà không ai ghi giả định "cần đọc cỡ mili giây".
Bài học cho SWE
- Dual write rồi shadow read bắt được khác biệt về giá trị; phải theo dõi thêm hành vi (độ dài vòng lặp), không chỉ độ khớp và latency từng truy vấn.
- Loại yêu cầu latency khỏi thiết kế (đồng thời, chịu số liệu hơi cũ) bền hơn tìm hằng số gom batch gắn với số đo hôm nay. Tải của chính cơ chế so sánh cũng phải tính.
Liên quan
#Vercel#build warm pool#Redis#DynamoDB#migration trực tiếp#dual write#shadow read#feature flag#schema theo access pattern#N+1#supply loop#P95
Được nhắc tới trong
Công ty (1)