The Great Re-shard: adding Postgres capacity (again) with zero downtime
Bài tóm tắt Notion 2023 3. Quy mô lớn Độ khó: Khó
Notion · 2023 · 3. Quy mô lớn · Độ khó: Khó — bài gốc
Bài ngoài sheet. Phần tiếp hai năm sau Notion 2021.
Bối cảnh
- Cụm "space shards" lưu toàn bộ nội dung workspace (block, comment, collection), chia theo workspace ID: 32 DB Postgres, mỗi DB chứa 15 logical schema; mỗi workspace nằm trọn trên một shard. Giữa web server và DB là PgBouncer (khoảng 100 instance, mỗi cái mở tới 6 kết nối vào mỗi shard, tức 600 kết nối/shard).
- Cuối 2022: vài shard vượt 90% CPU lúc cao điểm, nhiều shard gần chạm trần IOPS đã cấp, PgBouncer chạm giới hạn kết nối; trong khi đỉnh traffic đầu năm mới sắp tới.
Thay đổi chính
- Chọn scale ngang chứ không dọc: máy to hơn chỉ hoãn vấn đề, và nhiều máy nhỏ cho phép chỉnh từng instance theo tải thật (shard nóng khác shard nguội). Sau capacity planning: 32 → 96 máy, instance và đĩa nhỏ hơn để giữ chi phí (đĩa chưa phải nút thắt, nới sau được).
- Nhờ logical schema có sẵn: không phải chia lại dữ liệu theo key; chỉ dời schema, từ 15 xuống 5 schema mỗi shard. Hạ tầng dựng bằng Terraform.
- Đồng bộ: logical replication của Postgres, mỗi DB cũ có 3 publication (mỗi cái 5 schema), mỗi DB mới subscribe một cái. Bỏ tạo index lúc chép rồi dựng lại sau làm thời gian đồng bộ giảm từ 3 ngày xuống 12 giờ.
- Shard luôn tầng PgBouncer trước: thêm 96 entry trỏ tạm về 32 DB cũ sẽ làm mỗi PgBouncer mở 18 kết nối vào mỗi shard cũ; giảm kết nối thì query bị dồn. Lời giải: tách PgBouncer thành cụm riêng cho mỗi DB không shard và cho mỗi nhóm 24 shard (4 nhóm), chuyển dần ở load balancer theo từng bước nhỏ, chờ kết nối rút hết.
- Dark read: trên một mẫu nhỏ request, đọc song song từ DB mới (chờ 1 giây cho replication đuổi kịp) và so với primary; chỉ so query trả tối đa 5 dòng vì thêm CPU vào đường nóng ở quy mô production làm tăng latency. Kết quả khớp gần 100% (phần lệch có lẽ do query không tất định như
LIMIThoặc trễ replication). - Failover từng DB bằng script: tạm dừng traffic ở PgBouncer và để query đang chạy xong → kiểm tra replication đã đuổi kịp → đổi mapping sang DB mới, thu quyền đăng nhập của ứng dụng vào DB cũ, đảo chiều replication (DB mới sao chép ngược về DB cũ) → mở lại traffic. Mỗi bước có checkpoint và đường lùi; tập dượt nhiều lần ở staging.
Kết quả (theo Notion)
- Không có downtime người dùng nhận thấy; tệ nhất khoảng một giây biểu tượng "đang lưu". CPU và IOPS giảm mạnh. Chia tải ra nhiều máy hơn lại làm lộ rõ các workspace ngoại lai chiếm CPU quá mức trên một số shard.
Bài học cho SWE
- Chia dữ liệu thành nhiều logical schema hơn số máy ngay từ đầu biến resharding thành dời schema, không phải chia lại key.
- Tầng proxy/pool kết nối cũng có trần; khi nhân số shard phải tính lại số kết nối.
- Replication ngược sau cutover là đường lùi rẻ và đáng tin.
- Shard nhỏ hơn làm tenant lớn nổi bật hơn: resharding đều không giải được tenant khổng lồ.
Liên quan
- Multi-tenancy và cô lập tenant
- Notion 2021 (lần shard đầu, 2021) · Figma 2024 · Shopify 2018
- Sharding và tách database · Migration không downtime
#Resharding#Postgres#32 → 96 shard#Logical schema#Logical replication#Index rebuild#PgBouncer sharding#Dark read#Failover#Reverse replication#Zero downtime
Được nhắc tới trong
Chủ đề (4)
Công ty (1)
Bài tóm tắt (1)