- Khi thiết kế hệ thống, trên thực tế gần như không thể đồng thời thỏa mãn tính nhất quán hoàn hảo, tính sẵn sàng, độ trễ thấp và thông lượng cao
- Điều quan trọng là tìm ra thiết kế phù hợp bằng cách xác định điểm cân bằng thích hợp cho ứng dụng
- Trong thiết kế feed/timeline đang theo dõi của Bluesky, họ áp dụng một sự đánh đổi là hy sinh một phần tính nhất quán để cải thiện hiệu năng ghi
- Kết quả là độ trễ P99 giảm hơn 96% mà không gây ảnh hưởng tiêu cực đến người dùng
Fanout timeline
- Khi người dùng đăng bài trên Bluesky, bài viết sẽ được hệ thống lập chỉ mục, lưu vào cơ sở dữ liệu và được cung cấp qua phản hồi API
- Đồng thời, bài viết này trải qua quá trình “fanout” để chèn vào bảng timeline của từng người theo dõi
- Việc này được thực hiện bằng cách truy vấn danh sách người theo dõi rồi chèn theo thứ tự ngược vào bảng timeline của từng người
- Bảng timeline được phân vùng theo từng người dùng và lưu trong cơ sở dữ liệu phân tán (ScyllaDB), đồng thời được sao chép sang nhiều shard để đảm bảo tính sẵn sàng cao
- Mỗi người dùng có thể được gán vào các shard khác nhau
- Để tiết kiệm dung lượng lưu trữ, các timeline vượt quá một độ dài nhất định sẽ định kỳ xóa các tham chiếu đến bài viết cũ
Vấn đề hot shard
- Bluesky có khoảng 32 triệu người dùng, và cơ sở dữ liệu timeline được chia thành hàng trăm shard
- Trong một hệ thống có hàng triệu người dùng, có thể tồn tại những người dùng có số quan hệ follow cực lớn
- Ví dụ: người dùng follow hàng trăm nghìn tài khoản
- Một shard lưu trữ timeline của nhiều người dùng cùng lúc
- Nếu một người dùng cụ thể tạo ra quá nhiều ghi, shard đó sẽ rơi vào trạng thái quá tải (“hot shard”)
- Các hot shard như vậy khiến các thao tác đọc hoặc ghi bị dồn vào, làm độ trễ lan sang cả những người dùng khác trên cùng shard
Tích lũy độ trễ
- Nếu một người dùng có 2.000.000 người theo dõi, việc ghi tuần tự có thể mất hơn 20 phút
- Để giảm thời gian này, fanout có thể được song song hóa để rút ngắn độ trễ trung bình
- Tuy nhiên, độ trễ P99 (khoảng từ 15 mili giây trở lên) có thể xảy ra nhiều lần và làm chậm toàn bộ tác vụ song song
- Khi số người theo dõi rất lớn, độ trễ P99 hoặc P99.9 có thể khiến tổng thời gian fanout trong trường hợp xấu nhất tăng từ vài phút lên đến hàng chục phút
Timeline Lossy (mất mát)
- Với những người dùng follow quá nhiều tài khoản, việc hiển thị mọi bài viết theo đúng thứ tự một cách chính xác là điều không thực tế
- Trên thực tế, con người cũng khó có thể tiêu thụ hết toàn bộ số bài viết đó
- Vì vậy, với timeline của những người dùng có số lượng follow vượt quá một ngưỡng nhất định (ví dụ:
reasonable_limit), Bluesky áp dụng cách xác suất “drop” một phần thao tác ghi
- Công thức được sử dụng là
loss_factor = min(reasonable_limit / num_follows, 1)
- Trong lúc fanout, hệ thống tạo một giá trị ngẫu nhiên và nếu giá trị đó lớn hơn
loss_factor thì sẽ bỏ qua thao tác ghi vào timeline
- Nhờ đó có thể giới hạn lượng ghi quá mức vào timeline của một người dùng cụ thể và ngăn hiệu năng toàn shard bị suy giảm
Về caching
- Vì số lần ghi timeline vượt quá một triệu mỗi giây, nếu ở mỗi lần ghi lại truy vấn trực tiếp số lượng follow của người dùng từ DB thì tải sẽ rất lớn
- Thay vào đó, họ cache các tài khoản có số lượng follow cao trong Redis dưới dạng sorted set
- Các instance của dịch vụ fanout sẽ nạp thông tin cache này vào bộ nhớ mỗi 30 giây
- Kết quả là ngay trong quá trình fanout, hệ thống vẫn có thể tra cứu nhanh thông tin về người dùng có lượng follow cao
- Vì thông tin cache không nhất thiết phải hoàn toàn mới nhất, đây là một cách tiếp cận chấp nhận một chút không hoàn hảo để tăng hiệu năng và khả năng mở rộng
Kết quả
- Sau khi áp dụng timeline lossy, các hot shard trong cơ sở dữ liệu Timelines gần như biến mất
- Độ trễ P99 để xử lý một trang fanout giảm hơn 90%
- Xét toàn bộ công việc fanout, những tác vụ từng mất 5~10 phút theo chuẩn P99 đã được rút xuống dưới 10 giây
- Điều này cho thấy rằng ngay cả khi hy sinh một phần tính nhất quán, vẫn có thể đáp ứng đầy đủ kỳ vọng của người dùng dịch vụ và duy trì khả năng mở rộng ở quy mô lớn
- Kiến trúc timeline của Bluesky vẫn còn chỗ để cải thiện, nhưng thay đổi lần này đã cải thiện đáng kể thông lượng ghi và khả năng mở rộng
1 bình luận
Ý kiến trên Hacker News
Là người yêu thích hệ thống, tôi rất thích những bài như thế này. Rất dễ rơi vào lối nghĩ rằng "mọi thứ phải hoàn hảo"
Tôi thắc mắc vì sao không triển khai timeline theo kiểu hybrid dựa trên độ nổi tiếng của tài khoản
Đây là một lời giải thú vị cho một bài toán thú vị. Cảm ơn vì đã chia sẻ
Tôi tò mò về chiến lược hy sinh tính nhất quán này. Cũng muốn biết liệu có suy nghĩ nào về các cách khác ngoài fan-out hoàn toàn ở phía đọc hoặc ghi không
Không nhất thiết phải cung cấp mọi thứ mà hàng nghìn người một người dùng theo dõi đã đăng theo đúng thứ tự thời gian tuyệt đối, nhưng việc cung cấp đủ nội dung để timeline luôn có nội dung mới thì là hợp lý
Tôi tự hỏi việc giới hạn số follower để tránh vấn đề hot shard sẽ hoạt động thế nào
AWS có một cách tiếp cận tổng quát khá hay cho bài toán này
Các tài khoản theo dõi hàng trăm nghìn người dùng rõ ràng là bot cào nội dung. Tôi sẽ chặn luôn cho xong
Khi vào thẳng hồ sơ của một người dùng để xem tất cả bài đăng, đôi khi có những bài đáng lẽ phải có trong timeline nhưng lại không có
Tôi thắc mắc vì sao họ triển khai fan-out theo cách mỗi "trang" lại chặn việc lấy trang tiếp theo