← Tình huống

Đấu giá trực tiếp, tỷ số và lượng khán giả lớn

Đẩy giá đặt hoặc tỷ số hiện tại tới hàng nghìn người xem cùng lúc, cho người mới vào thấy ngay trạng thái mới nhất và hiện số “đang xem” thật.

Đấu giá trực tiếp, tỷ số thể thao, game show đố vui, flash sale và bình luận trên livestream có một điểm chung: hàng nghìn người xem cùng một thứ vào cùng một lúc, và một giây chậm trễ có thể thay đổi kết quả. Một giá đặt đến muộn hay tỷ số chậm hơn sóng truyền hình sẽ đẩy người xem sang nơi khác.

Người dùng nhận được gì

  • Giá đặt, tỷ số hoặc tồn kho hiện tại ngay khi thay đổi.
  • “12.408 người đang xem”, một con số thật và luôn chuyển động.
  • Trạng thái mới nhất ngay khi mở trang, kể cả khi sự kiện đã diễn ra được một nửa.

Dùng những gì

  • Kênh cache (cache-), để mọi người mới vào nhận ngay giá hoặc tỷ số hiện tại mà không chạm tới cơ sở dữ liệu của bạn.
  • Kênh presence lớn (presence-large-), tối đa 100.000 thành viên, kèm số lượng trực tiếp và một mẫu danh sách người đang có mặt.
  • Số người đăng ký (pusher:subscription_count) cho bộ đếm người xem đơn giản trên kênh công khai.
  • Phát tán miễn phí: một giá đặt phát tới 20.000 người xem chỉ tính một tin nhắn, không phải 20.000.

Bước 1: phát mỗi thay đổi một lần

Máy chủ của bạn kiểm tra giá đặt hoặc ghi nhận tỷ số, rồi phát trạng thái mới cho mọi người:

app.post('/auctions/:id/bids', requireLogin, async (req, res) => {
  const bid = await db.auctions.placeBid(req.params.id, req.user.id, req.body.amount); // rejects lower bids
  await pusher.trigger(`cache-auction-${req.params.id}`, 'bid', {
    amount: bid.amount,
    bidder: bid.displayName,
    endsAt: bid.endsAt,
  });
  res.json(bid);
});

Luôn gửi toàn bộ trạng thái (số tiền hiện tại và giờ kết thúc), không gửi phần chênh lệch: người xem lỡ một sự kiện sẽ đúng trở lại ở sự kiện tiếp theo.

Bước 2: hiển thị cho khán giả

const auction = pusher.subscribe(`cache-auction-${id}`);
auction.bind('bid', ({ amount, bidder, endsAt }) => {
  price.set(amount);
  feed.prepend(`${bidder} bid ${amount}`);
  countdown.until(endsAt);
});

Giá đặt cuối cùng trong cache đến ngay sau khi đăng ký, nên giá không bao giờ trống.

Bước 3: bộ đếm người xem

Nếu chỉ cần con số, bật Gửi số người đăng ký trong cài đặt ứng dụng và lắng nghe sự kiện số lượng trên cùng kênh công khai:

auction.bind('pusher:subscription_count', ({ subscription_count }) => watching.set(subscription_count));

Không cần viết mã, đoạn script nhúng một dòng làm được điều tương tự: <span data-hibira-online="cache-auction-42">0</span> watching.

Để hiển thị cả ai đang có mặt, dùng kênh presence lớn cùng @hibira-io/large-presence:

import { LargePresence } from '@hibira-io/large-presence';

const room = LargePresence.subscribe(pusher, `presence-large-auction-${id}`, { maxMembers: 50 });
room.on('ready', ({ count }) => audience.render(count, room.members));
room.on('change', ({ count }) => audience.render(count, room.members));

Số lượng luôn chính xác, còn các lượt vào và ra của thành viên được gộp thành một cập nhật nhỏ mỗi giây thay vì một sự kiện cho mỗi người.

Mẹo

  • Kiểm tra mọi giá đặt, câu trả lời hay giao dịch mua trên máy chủ. Không bao giờ để client tự phát trạng thái của sự kiện.
  • Hãy lên kế hoạch theo số kết nối, không phải số tin nhắn: 20.000 người xem là 20.000 kết nối đồng thời, và giá phụ thuộc vào mức cao điểm. Xem bảng giá.
  • Với khoảnh khắc cháy hàng như mở bán vé, hãy phát số tồn kho mỗi một đến hai giây thay vì sau mỗi lần bán.
  • Thử với đúng quy mô khán giả trước ngày quan trọng: mở nhiều kết nối bằng công cụ kiểm thử tải và theo dõi trang ứng dụng trong cổng khách hàng.