← 使用场景

实时拍卖、比分与大量观众

把当前出价或比分同时推给成千上万名观众,让新进来的人立刻看到最新状态,并显示真实的“正在观看”人数。

实时拍卖、运动比分、益智节目、限时抢购和直播留言有一个共同点:成千上万的人在同一刻看同一件事,晚一秒就会改变结果。晚到的出价、落后转播的比分,都会把人送去别的地方。

用户得到什么

  • 目前出价、比分或库存一变化就立刻看到。
  • “12,408 人正在观看”,一个真实而且会动的数字。
  • 一打开页面就看到最新状态,即使活动已经进行到一半。

用到的功能

  • 缓存频道(cache-),每位新进来的人立刻拿到目前的价格或比分,不必查你的数据库。
  • 大型 presence 频道(presence-large-),最多 100,000 名成员,提供实时人数与在场者样本。
  • 订阅人数(pusher:subscription_count),在公开频道上显示简单的观看人数。
  • 免费扇出:一次出价发布给 20,000 名观众,只算一条消息,不是 20,000 条。

步骤 1:每次变化只发布一次

你的服务器检查出价或记录比分,然后把新状态发布给所有人:

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);
});

永远送完整状态(目前金额与结束时间),不要送差异:漏掉一个事件的观众,在下一个事件时就会恢复正确。

步骤 2:显示给观众

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

订阅后马上会收到缓存的最后一次出价,价格永远不会是空白。

步骤 3:观看人数

如果只需要人数,在应用设置里打开 发送订阅人数,并在同一个公开频道上绑定人数事件:

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

不写程序也行,一行嵌入脚本可以做到同样的事:<span data-hibira-online="cache-auction-42">0</span> watching。

如果还要显示有谁在场,使用大型 presence 频道与 @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));

人数始终精确,成员的加入与离开则每秒合并成一个小更新送达,而不是每个人一个事件。

小提醒

  • 每次出价、答案或购买都在你的服务器上验证。绝对不要让客户端自己发布活动的状态。
  • 要规划的是连接数,而不是消息数:20,000 名观众就是 20,000 个同时连接,价格取决于峰值。请看价格。
  • 像抢票开卖这种瞬间,每一两秒发布一次库存,而不是每卖出一张就发一次。
  • 大日子之前先用真实的观众规模测试:用压力测试工具开大量连接,同时在 portal 的应用页面观察。