大班课答题器实时统计做得稳不稳,关键不在前端那张柱状图,而在服务端推送链路怎么设计把答题事件聚合成秒级快照,通过长连接推给老师端,才是大班场景的正确解法。会从协议选型、链路拆解、成本对比、地域部署到线上排障,给出可直接落地的做法。
大班课答题器实时统计为什么必须走服务端推送而不是轮询
一个直播间里同时有几百上千人在点选项,如果客户端每隔一两秒去问一次服务器“现在统计是多少”,问题会成倍放大。
轮询在大班课场景下的三个硬伤
- 连接风暴:5000 人在线、每 2 秒轮询一次,入口就是 2500 QPS,而且这些请求大多返回相同内容。
- 延迟不确定:老师看到的数据永远滞后一个轮询周期,答题结束瞬间的“抢答统计”最容易失真。
- 带宽浪费:HTTP 头、TLS 握手、重复的 JSON 结构,在移动网络下成本明显。
WebSocket、SSE、长轮询怎么选
业内专家指出,实时统计这类“服务端主动、消息小、频率可控”的场景,全双工长连接并不是唯一答案,单向推送往往更省。
| 方案 | 方向 | 兼容性 | 单机承载 | 适用场景 |
|---|---|---|---|---|
| WebSocket | 双向 | 现代浏览器与 App 均支持 | 较高,受内存和文件描述符限制 | 需要客户端回执、心跳、答题上报共用一条连接 |
| SSE(EventSource) | 服务端到客户端单向 | 不支持自定义请求头,老版本 IE 不可用 | 较高 | 只推统计结果,答题走普通 POST |
| 长轮询 | 伪推送 | 最好 | 较低 | 弱网兜底、老旧设备降级 |
实操建议:主链路用 WebSocket(协议标准见 RFC 6455),把答题上报和统计下发放在同一条连接里,省一次建连;SSE 作为二级备选;长轮询只在检测到连接连续失败时启用 3 秒一次的降级轮询。
从学生按下选项到老师端刷新:一条推送消息的完整链路
消息产生:答题上报带上批次与序列号
学生端提交的负载尽量小:
POST /api/answer
{"roomId":"r1024","qid":"q7","opt":"B","uid":"u88231","ts":1730000000123}
服务端为每个房间维护递增 seq,客户端断线重连时带 lastSeq,只补发缺失区间,避免重复渲染造成“票数跳变”。
服务端聚合:先写计数,再生成快照
- 用 Redis 的
HINCRBY room:{roomId}:q:{qid}:opt B 1累加选项票数,配合 Lua 脚本保证“写票数 + 记录去重键”原子执行。 - 同一用户同一题只计一次,去重键设 30 分钟过期,防止网络重试导致重复计票。
- 每 500 毫秒由聚合任务读一次当前计数,生成快照消息,而不是每来一票就推一次,这是大班课控住推送量的核心:票数增长是高频的,老师端可感知的刷新是低频的。
推送分发:房间分片加跨节点广播
单机扛不住时,按 roomId % N 把房间固定到某个网关节点,同一房间的连接落在同一台机器,扇出就变成一次本地广播,跨节点统计用 Redis Pub/Sub 或消息队列同步快照,注意消费端要做幂等,按 seq 丢弃旧消息。
客户端渲染:版本号加幂等
快照消息建议带上 rev 字段,前端只接受比当前 rev 大的消息,网络抖动引起的乱序就不会让柱状图来回跳。
大班课答题器服务端推送方案对比:自建网关还是买云服务
这是选型时最容易吵起来的问题,答案取决于规模曲线。
| 维度 | 自建长连接网关 | 云厂商推送/实时通信服务 |
|---|---|---|
| 起步成本 | 一台 8 核 16G 机器加负载均衡即可 | 按连接数和消息量计费,小规模更省心 |
| 扩容方式 | 手动加节点、改分片、迁移房间 | 控制台调整规格,连接自动重分布 |
| 运维负担 | 需要自己处理心跳、重连、内存泄漏 | 厂商承担,但排障黑盒 |
| 数据合规 | 数据完全自持 | 需确认存储地域与日志归属 |
| 适合阶段 | 日活稳定、技术团队有长连接经验 | 快速验证期、活动型大班课 |
价格上,按连接数计费的产品在十万级并发时月度账单通常已到数千元量级,而同等规模自建主要花在带宽和人力上,行业共识认为,答题器这类功能单一、消息体极小的模块,自建网关的边际成本更低;但如果团队没有长连接运维经验,先买服务跑通业务更稳。
大班课答题器实时统计服务端部署在哪个地域延迟低
地域选择直接影响老师端的“手感”,据工信部公开的通信业统计,国内宽带与移动网络的平均速率近年持续提升,但跨地域跨运营商的抖动依然是长连接掉线的主要来源。
就近接入与多机房
- 学生端接入点按用户所在区域调度,华东、华北、华南各设一个接入机房,回源到同一套聚合服务。
- 老师端单独走一条低延迟线路,因为老师端连接数少但对刷新敏感。
- 同城双活优先于异地多活,统计类数据允许秒级不一致,但房间归属必须唯一,避免两个机房同时累加。
怎么实测地域延迟
不要凭感觉选机房,用可验证的方式:
ping与mtr -r -c 100 目标IP看丢包和抖动,重点看第 3 跳到第 6 跳。- 在目标机房起一个测试 WebSocket 服务,用
wscat -c wss://测试域名/ws连续发 200 次心跳,记录 RTT 分布。 - 对比接入点:同一城市不同运营商的移动网络各测一遍,取 P95 而不是平均值。
推送链路稳定性:心跳、重连、限流与降级
网关配置的关键几行
Nginx 反代 WebSocket 至少要这几项,路径一般在 /etc/nginx/conf.d/ws.conf:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 60s;
proxy_send_timeout 60s;
心跳建议服务端 25 秒发一次 ping,60 秒内没收到 pong 就主动断开,让客户端走重连,避免半开连接占着内存。
重连策略
- 指数退避:1s、2s、4s、8s,上限 30s,加 ±20% 随机抖动,防止断网恢复瞬间全体重连打爆入口。
- 重连带
lastSeq与房间号,服务端只补差异快照,不重放全量。 - 单连接限流:答题上报 1 次/秒,超出直接丢弃并记录,防止脚本刷票。
线上排查常用命令
ss -s看连接总数与 TIME_WAIT 堆积。netstat -anp | grep :8080 | wc -l核对单机连接数是否接近上限。tcpdump -i eth0 port 443 -w ws.pcap抓包后用 Wireshark 看握手与心跳间隔。- 压测用 k6:
k6 run --vus 5000 --duration 1m ws_test.js,重点看 P95 建连耗时和消息到达延迟。
统计口径要统一
“应答率”到底按在线人数算还是按进入答题页人数算,必须在需求评审时定死并写进接口文档,多数情况下,老师看到的数字和后台报表对不上,不是推送丢了,而是分母口径不一致。
关于大班课答题器实时统计服务端推送的Q&A
Q1:大班课答题器服务端推送的并发量怎么估算?
按“同时在线人数 × 峰值同时答题比例”估连接数,按“连接数 ÷ 快照周期”估推送消息量,一场万人课,若 500 毫秒一帧快照、只推老师端,消息量其实很小,压力主要在连接维持而不是带宽。
Q2:学生端断线后统计会不会漏票?
会漏,但可以补,答题上报走独立 HTTP 接口并落库,推送只负责展示;重连时用 lastSeq 拉一次最新快照即可对齐,真正要防的是重复计票,去重键必须放在聚合写入的同一次原子操作里。
Q3:小团队没有长连接经验,最快跑通的做法是什么?
先上 SSE 或 WebSocket 单机版,房间分片留到连接数逼近单机瓶颈再做;聚合逻辑放在 Redis,快照周期从 1 秒起步,观察老师端反馈再缩短,等业务稳定、并发上来,再评估自建网关与云服务的成本差。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/771324.html


