Inside Stream's Real-Time Architecture for Trading & Investing Apps

Bài tóm tắt Stream (GetStream) 2026 3. Quy mô lớn Độ khó: Trung bình

Stream (GetStream) · 2026 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc

Bài của nhà cung cấp (Stream bán API Feeds/Chat/Video), giọng tiếp thị; số liệu là benchmark tự chạy, không phải tải production của khách. Wiki giữ phần kiến trúc feed và chat; mọi nhận định ghi "theo Stream".

Bối cảnh

  • Theo Stream, app giao dịch có hai "mặt phẳng" realtime: giao dịch (lệnh, khớp, sổ cái; cần thứ tự, idempotency, kiểm toán) và trải nghiệm (feed, thông báo, chat, video; cần fan-out toàn cầu và latency cảm nhận thấp). Backend giao dịch quyết định chuyện gì xảy ra và publish event (OrderFilled, PriceThresholdCrossed); mặt phẳng trải nghiệm chỉ phân phối.
  • Tải dồn vào giờ mở cửa thị trường: một mức giá được nhiều người theo dõi sinh hàng nghìn cảnh báo cùng lúc, và mọi người mở app cùng lúc.

Thay đổi chính

  • Feed: fan-out on read có cache ("materialized feed"). Mỗi activity lưu một lần (không chép theo follower như push). Khi đọc, chỉ lấy phần mới kể từ lần đọc trước nhờ cursor cho từng nguồn được theo dõi, rồi merge vào kết quả đã cache trong TiKV (TiKV lo multi-Raft và rebalance mà trước đây Stream tự vận hành). Lúc dựng top N, nguồn nào không còn gì đủ mới thì ngừng xét. Khoá aggregation tính lúc ghi; ranking tính lúc đọc trên bản tóm tắt nhẹ của activity.
  • Bảng so sánh theo Stream: push đọc 1–5 ms nhưng ghi một bản mỗi follower (tài khoản hai triệu follower = hai triệu lần ghi) và ghi phí cho user không hoạt động; pull ghi rẻ nhưng đọc 100–500 ms; materialized feed ghi một lần, đọc khoảng 10 ms.
  • Các lớp cache trước storage: Redis client-side caching trong process API; Ristretto + singleflight chống cache stampede (khoá nóng hết hạn thì một request dựng lại, số còn lại chờ); "hot feed cache" tuỳ chọn phục vụ một thứ tự chung cho mọi người đọc feed chung (kiểu "mã được bàn nhiều nhất hôm nay"); cuckoo filter kiểm tra user có đang kết nối với server không trước khi push.
  • Chat: client nối vào edge gần nhất (handshake, xác thực, rate limit tại edge), edge → origin qua kết nối mở sẵn; SDK giữ trạng thái cục bộ để app mở lên ngay. Message được serialize một lần rồi gửi từng người nhận.
  • Video: SFU thay peer-to-peer; luồng 100.000 người xem cần hơn 200 Gbps nên cascade SFU theo vùng (mỗi SFU khoảng một nghìn người xem), simulcast, chống thundering herd lúc join.
  • Benchmark tự chạy (theo Stream, 2026): 4,5 triệu user đồng thời trên 500 triệu activity, 200 triệu quan hệ follow: đọc feed p50 khoảng 15 ms, ghi khoảng 31 ms, p99 dưới 140 ms. Một kênh chat 5 triệu người: khoảng 15 triệu lượt giao message mỗi giây lúc đỉnh, gửi trung bình dưới 40 ms.

Vì sao

  • App đầu tư có cả hai bài toán fan-out: tài khoản/mã cổ phiếu có hàng triệu follower (push đắt) và cú đọc dồn lúc 9:30 (pull đắt). Cache kết quả pull và chỉ đọc phần chênh giữ được cả hai đầu.

Bài học cho SWE

  • Tách đường "đúng" (giao dịch, idempotent, có thứ tự) khỏi đường "phân phối" (fan-out, chịu được trễ nhỏ); đường phân phối không bao giờ quyết định trạng thái.
  • Fan-out on read + cache có cursor theo nguồn là điểm giữa giữa push và pull, nhưng phải trả bằng một kho cache bền đủ lớn.
  • Khoá nóng hết hạn đồng loạt là chuyện chắc chắn xảy ra lúc tải đỉnh; singleflight là phòng thủ mặc định.

Liên quan