Re-architecting Slack's Workspace Preferences: Moving to an EAV Model
Bài tóm tắt Slack 2018 3. Quy mô lớn Độ khó: Dễ
Slack · 2018 · 3. Quy mô lớn · Độ khó: Dễ — bài gốc
Bối cảnh
- Thiết kế ban đầu: lưu tuỳ chọn của workspace dưới dạng một JSON blob ngay trong bảng
workspaces(MySQL). Hợp lý khi Slack còn nhỏ. - 2018: 165 tuỳ chọn, 150+ tổ chức Enterprise Grid, 70.000+ workspace trả phí, 8 triệu DAU. Blob có thể vượt 55 KB.
- Vấn đề:
- code thường chỉ cần một tuỳ chọn nhưng phải đọc cả bảng
workspaces, vốn đã bị truy cập rất nhiều cho thông tin sống còn; - cache lưu cả object workspace, nên đọc một tuỳ chọn là kéo cả khối về Memcached, và đổi một tuỳ chọn là invalidate cả object.
- code thường chỉ cần một tuỳ chọn nhưng phải đọc cả bảng
- Bài do một thực tập sinh trong team Enterprise Architecture viết.
Thay đổi chính
- Mô hình EAV (entity/attribute/value): bảng mới
(workspace_id, pref_name, pref_value JSON), mỗi tuỳ chọn một hàng. Đọc một tuỳ chọn không kéo theo phần thừa; thêm tuỳ chọn không cần đổi schema. Đã cân nhắc và loại phương án mỗi tuỳ chọn một cột (đổi schema đắt mỗi lần thêm). Bảng tạo trên Vitess (Slack 2020). - Migration:
- không dùng được công cụ chép bảng có sẵn vì một hàng cũ tách thành nhiều hàng mới;
- viết hàm tách; ghi kép + script backfill, trong vài ngày bảng mới đã đầy đủ.
- Đọc:
- "dark mode": đọc cả hai, so sánh, vẫn trả về dữ liệu cũ, đo thời gian đọc bảng mới. Cách này lộ ra một bug có sẵn từ trước: hàm khởi tạo nhận workspace theo giá trị thay vì tham chiếu, nên tuỳ chọn ban đầu bị ghi đè;
- "light mode": trả dữ liệu mới, bật dần bằng feature flag (workspace test → Slack nội bộ → mọi user).
- Sinh code getter cho từng tuỳ chọn có kiểu trả về (một phần của việc chuyển sang Hack). Nhân tiện bổ sung kiểu cho 12 tuỳ chọn và tìm ra 14 tuỳ chọn không còn dùng.
- Cache từng tuỳ chọn riêng, nên đổi một tuỳ chọn chỉ invalidate đúng nó.
Kết quả
Invalidate cache workspace giảm đáng kể (bài không có số); thêm tuỳ chọn mới dễ hơn; kiểu dữ liệu an toàn hơn.
Vì sao
Theo Slack: một quyết định hợp lý lúc nhỏ (JSON blob) vỡ khi workspace lớn, và gây hại cho một bảng nóng mà nhiều phần khác dùng chung.
Bài học cho SWE
- Blob gom nhiều thứ vào một hàng nóng gây hại hai lần: tải đọc lên bảng chung và cache bị invalidate cả khối.
- Mẫu migration chuẩn ở quy mô nhỏ: ghi kép → backfill → đọc kép so sánh ("dark") → đọc mới bật dần ("light"). Cùng trình tự Slack dùng khi lên Vitess.
- Đọc kép so sánh còn bắt được bug không liên quan tới migration.
- Việc tái cấu trúc mô hình dữ liệu cũng là dịp dọn nợ (kiểu dữ liệu, tuỳ chọn chết).
Liên quan
Được nhắc tới trong
Chủ đề (4)
Công ty (1)
Bài tóm tắt (2)