How Discord Stores Billions of Messages
Bài tóm tắt Discord 2017 2. Tăng trưởng Độ khó: Trung bình
Discord · 2017 · 2. Tăng trưởng · Độ khó: Trung bình — bài gốc
Bối cảnh
- Bản đầu của Discord được viết trong chưa tới 2 tháng (đầu 2015). Mọi thứ nằm trong một replica set MongoDB, và họ nói rõ là cố ý: làm nhanh để kiểm chứng sản phẩm, nhưng luôn chừa đường sang giải pháp bền hơn. Họ biết trước sẽ không dùng sharding của MongoDB.
- Tháng 11/2015 đạt 100 triệu tin nhắn lưu trữ: dữ liệu và index (
channel_id, created_at) không còn vừa RAM, latency khó đoán. - Lúc viết bài (2017): hơn 120 triệu tin nhắn/ngày, chỉ có 4 kỹ sư backend, chưa có DevOps riêng.
Thay đổi chính
- Hiểu workload trước: đọc rất ngẫu nhiên, tỷ lệ đọc/ghi ~50/50. Ba kiểu server có mẫu truy cập khác hẳn nhau (server voice gần như không nhắn; server riêng tư ít người; server công khai lớn đọc tin trong giờ gần nhất liên tục).
- Đặt yêu cầu rồi mới chọn: scale tuyến tính, tự failover, ít bảo trì, đã được kiểm chứng, latency đoán trước được (cảnh báo khi p95 API > 80ms, không muốn cache tin nhắn trong Redis), không phải blob store, mã nguồn mở. Cassandra là lựa chọn duy nhất thỏa hết.
- Mô hình dữ liệu: khóa chính
((channel_id, bucket), message_id).message_idlà Snowflake (xem Sinh ID phân tán) nên sắp được theo thời gian;bucketlà cửa sổ ~10 ngày để mỗi partition dưới 100MB (khi import đã thấy partition > 100MB gây áp lực GC). - Dark launch: đọc/ghi kép vào MongoDB và Cassandra, rồi bỏ MongoDB trong vòng một tuần.
- Cụm ban đầu: 12 node, replication factor 3, ~1TB nén mỗi node. Ghi dưới 1ms, đọc dưới 5ms.
Vì sao
Theo Discord: dữ liệu + index không còn vừa RAM; họ cần một DB chỉ cần thêm node khi lớn, không phải tự reshard. Discord chọn Cassandra vì nó thỏa toàn bộ danh sách yêu cầu, và vì Netflix, Apple chạy hàng nghìn node.
Bài học cho SWE
- Eventual consistency có giá thật: mọi lệnh ghi Cassandra là upsert, nên sửa và xoá cùng lúc sinh ra hàng chỉ có khoá + text. Discord chọn phát hiện hàng hỏng (thiếu
author_id) rồi xoá. - Ghi
null= tạo tombstone. Schema 16 cột, trung bình chỉ 4 cột có giá trị, nên trước đó họ ghi 12 tombstone thừa mỗi tin. Sửa: chỉ ghi giá trị khác null. - "Big surprise" sau 6 tháng: một server công khai xoá hàng triệu tin, còn lại 1 tin; mỗi lần mở kênh Cassandra phải quét hàng triệu tombstone, gây GC stop-the-world 10 giây. Sửa: giảm thời gian sống tombstone từ 10 xuống 2 ngày (vì chạy repair mỗi đêm) và ghi nhớ bucket rỗng để bỏ qua.
- Đã nhìn trước hướng đi: thử ScyllaDB vì repair làm Cassandra nặng CPU. Đây chính là việc họ làm năm 2022, xem Discord 2023.
Liên quan
Chọn database theo workloadSharding và tách databaseHot partition và thundering herdMigration không downtimeSinh ID phân tán
Được nhắc tới trong
Chủ đề (5)
Công ty (1)
Bài tóm tắt (2)