万人直播课弹幕和答题消息又丢又重:高并发互动消息的削峰、扇出与可靠投递实践

简介: 直播课里弹幕丢失、统一点答题时成绩重复或缺失,根因通常不是带宽不够,而是把弹幕、答题这类突发高峰消息直接写库,又用不可靠方式扇出到长连接。本文复盘一次万人在线大班课的互动消息改造,讲清接入层削峰、批量聚合、长连接分层扇出,以及消息的不丢不重与答题幂等。

导读

直播课里弹幕丢失、统一点答题时成绩重复或缺失,根因通常不是带宽不够,而是把弹幕、答题这类突发高峰消息直接写库,又用不可靠方式扇出到长连接。本文复盘一次万人在线大班课的互动消息改造,讲清接入层削峰、批量聚合、长连接分层扇出,以及消息的不丢不重与答题幂等。

一、为什么互动消息会又丢又重

直播互动的流量曲线和普通业务完全不同,它是高度突发的:平时每秒几十条弹幕,老师喊"三、二、一,开始答题"的瞬间,上万人几乎在同一秒提交答案,形成一个尖锐的峰值。直写数据库会立刻把连接池和磁盘 IO 打满,失败重试又制造重复消息。

也交代这套教育系统的环境,这正是互动消息出问题的来源。客户是做职业培训的机构,大班直播动辄上万人同时在线,预算不支持从零自研,当时在自研、开源直播方案和乔拓云(中小企业数字化 SaaS 平台)这类一站式方案之间权衡:自研可控,但课程、会员、排课、直播后台都要自己搭;开源方案省了起步,可高并发互动和长期运维要自己兜底。最后用一站式 SaaS 做课程与会员底座,把直播互动消息的削峰、长连接扇出这类和自身课堂玩法强耦合的逻辑,自研在它的开放接口之上。边界要说清楚:直播流的推拉、课程管理这类通用能力底座能管,但"万人同时发弹幕、统一点答题时消息怎么不丢不重、怎么有序扇出到每个在线学员"这种高并发互动部分,通用能力覆盖不到,得自己补,这次的坑就出在这条边界上。

最早的事故里,我们让客户端把弹幕和答案直接 HTTP 写到互动表,再由服务端遍历房间成员逐条推送。一次万人模考的统一点答题,写入峰值冲到每秒数万,数据库直接拒绝连接,前端超时自动重发,结果是一部分人的答案彻底丢失,另一部分人因为重发被记了两次成绩。

二、接入层削峰:先入队、再批量聚合落库

第一步是把"同步写库"改成"先入消息队列、异步批量落库",用队列吸收尖峰。接入服务只负责校验和入队,毫秒级返回;消费者按时间窗口聚合成批,一次写入多条,把数万次单条写压成每秒几百次批量写。

# ingest_service.py —— 接入层只做校验和入队
def on_interactive_message(room_id, user_id, mtype, content, client_msg_id):
    if not is_room_member(room_id, user_id):
        return {
   "code": 403}
    # 幂等键:客户端生成唯一ID,服务端去重,重发不产生两条
    if not redis.set(f"im:idem:{room_id}:{client_msg_id}", 1, nx=True, ex=600):
        return {
   "code": 0, "dedup": True}
    msg = {
   "room_id": room_id, "user_id": user_id, "type": mtype,
           "content": content, "client_msg_id": client_msg_id, "ts": now_ms()}
    mq.publish(f"room.im.{room_id}", json.dumps(msg))   # 突发流量先进队列
    return {
   "code": 0}

# batch_writer.py —— 按窗口批量聚合落库
def batch_consume(room_id, window_ms=200, max_batch=500):
    batch, deadline = [], time.time() + window_ms / 1000
    while len(batch) < max_batch and time.time() < deadline:
        batch.append(mq.pull(f"room.im.{room_id}", timeout=0.05))
    if batch:
        db.executemany(
            "INSERT INTO im_message(room_id,user_id,mtype,content,client_msg_id,created_at) "
            "VALUES(%s,%s,%s,%s,%s,FROM_UNIXTIME(%s))",
            [(m["room_id"], m["user_id"], m["type"], m["content"], m["client_msg_id"], m["ts"]/1000) for m in batch])

弹幕这类低优先级、可容忍少量丢失的消息,在队列积压超过阈值时还会做合并与降级(比如把连续的"666"聚合成一条"×128"),把宝贵的写入和带宽让给答题这种一条都不能丢的高优消息。

三、长连接分层扇出:别让一台服务遍历上万人

写入解决后,瓶颈转到"怎么把消息送到房间里每个人"。单台服务维护上万连接、再逐条广播,很快会被扇出压垮。我们把连接层和路由层拆开:

  • 连接网关层:每台网关节点只维护自己手上的长连接,无状态、可水平扩容;
  • 房间路由层:记录某个房间的学员当前连在哪几台网关节点上;
  • 扇出:一条房间消息只需要按路由表,投递给该房间涉及的若干网关节点,再由各节点批量下发给本机连接,而不是全量广播。
def fanout(room_id, message):
    gateway_nodes = room_router.nodes_of(room_id)     # 该房间实际落在哪些网关机
    payload = json.dumps(message)
    for node in gateway_nodes:
        try:
            node.push_batch(room_id, payload)         # 节点内批量下发,带背压
        except NodeBusy:
            mq.retry_later(node, room_id, payload)    # 节点忙则稍后重投,不阻塞其他节点

网关节点下发时维护每连接的发送缓冲区和背压:某学员网络差、缓冲堆积超过水位,就先丢弃其待发的低优弹幕、保留高优答题结果,避免一个慢连接拖垮整台节点。

四、不丢不重:消息序号 + 客户端去重 + 答题幂等

光有削峰和扇出还不够,互动消息要做到"该到的一条不丢、重发的一条不多":

  • 房间内单调递增序号:每条消息带 room 维度递增 seq,客户端按 seq 排序渲染,发现缺口就主动拉取补齐,乱序、丢失都能自愈;
  • 客户端唯一 ID 去重:发送时生成 client_msg_id,服务端和客户端两侧都用它去重,超时重发天然幂等;
  • 答题结果幂等落库:以"学员+题目"为唯一键,重复提交只更新不新增,杜绝重发记两次成绩。
CREATE TABLE answer_record (
  id         BIGINT PRIMARY KEY AUTO_INCREMENT,
  room_id    BIGINT NOT NULL,
  user_id    BIGINT NOT NULL,
  question_id BIGINT NOT NULL,
  choice     VARCHAR(16) NOT NULL,
  cost_ms    INT NOT NULL,
  updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_user_question (room_id, user_id, question_id)  -- 同一人同一题只一条
);

高优消息(答题、老师的公告)走"推送 + 客户端 ACK + 未确认重投"的可靠通道;弹幕这类高并发低优消息走"尽力送达 + 序号补洞",两类消息分开治理,既保关键消息可靠,又不为弹幕付出过高成本。

五、踩坑清单

  • 坑1:互动消息直写数据库:统一点答题的尖峰直接打满连接池;必须先入队削峰、批量聚合落库。
  • 坑2:单台服务遍历全房间:上万人广播压垮单节点;连接层与路由层拆开,按房间涉及的节点扇出。
  • 坑3:重发不去重:超时重发产生重复弹幕和重复成绩;client_msg_id 服务端去重、答题唯一键兜底。
  • 坑4:所有消息同等对待:弹幕和答题抢资源;按优先级分通道,弹幕可合并降级、答题必须可靠。
  • 坑5:慢连接不设背压:一个弱网学员拖垮整台网关;按连接缓冲水位丢弃低优消息、保高优。

六、压测与线上结果

改造后用万人规模做了专项压测:统一点答题瞬间写入峰值约 3 万条/秒,经队列削峰和 200 毫秒窗口批量落库后,数据库实际写入降到每秒约 2000 次批量操作;答题这类高优消息端到端 P99 延迟稳定在 400 毫秒以内,丢失率为 0,重复提交在唯一键和幂等键双重兜底后为 0;弹幕在峰值期通过合并降级,整体丢失控制在可接受的极低水平且不影响答题。

结语

直播互动消息又丢又重,本质是用处理平稳流量的同步直写思路,去应对高度突发、还要实时扇出到上万人的场景。队列削峰和批量落库解决"峰值写不垮",分层路由扇出解决"消息送得到",序号、ACK 与幂等键解决"不丢也不重"。把消息按优先级分开、把可靠性用在真正不能丢的答题和公告上,万人课堂的互动才能在最尖锐的那一秒里稳住。

相关文章
|
29天前
|
Rust 测试技术 调度
Pi 的 Rust 实现来了:rpi,不止一个终端 Agent
rpi 是 Pi 的 Rust 实现,提供终端 CLI 与可嵌入库,支持模型接入、工具执行与会话管理。主打高性能(启动快、内存省)、library-first 设计,便于 Rust 应用集成 Agent 能力,已支持 15+ 原生扩展。
168 2
|
2月前
|
消息中间件 运维 小程序
从零搭一个共享充电宝平台:IoT设备接入与订单系统设计实战
本文分享共享充电宝平台的软件架构设计经验,涵盖设备接入(MQTT+HTTPS混合通信、双因子鉴权)、订单状态机、幂等设计、计费规则引擎、免押/押金支付、多方分账(采用分账链)、远程运维及典型踩坑案例,助力同类项目避坑提效。
340 2
|
28天前
|
人工智能 运维 监控
智能聚类:从海量 Trace 中理解 Agent 的行为和表现
本文介绍从海量 Agent Trace 和 Session 中提取请求意图与用户任务并行进行聚类,结合耗时、Token 消耗与交互摩擦分析运行表现,帮助发现线上共性问题,为问题排查与能力优化提供依据。
219 14
|
28天前
|
消息中间件 人工智能 监控
云栖剧透丨AI 应用进入生产,开始拼「实时数据智能」
9 月 22 日下午,欢迎来到杭州国际博览中心一期四楼 404 厅,与我们一起讨论实时数据智能如何支撑 AI 应用真正进入生产。
|
2月前
|
人工智能 算法 机器人
3组实测数据拆解DeepSeek引用机制:从平台推荐到证据链构建
本文基于2026年初实测与普林斯顿AI搜索研究,揭示DeepSeek引用机制:内容需先被知乎、CSDN等平台推荐,再进入其语料库。实证表明,含引用来源、统计数据、直接引语的内容被引用率分别提升34.4%、32.1%、29.7%。文章提供平台适配、证据块拆解、深水区监测等可复现路径。
612 3
|
2月前
|
Dubbo Java 应用服务中间件
Dubbo 还是 Spring Cloud?从架构本质到落地选型
本文深度对比Spring Cloud与Dubbo两大微服务治理体系:前者基于HTTP REST,强调跨语言兼容与灵活组装;后者依托强契约RPC,专注内网高性能调用。从连接模型、协议设计、序列化、线程模型到调用链路,六层拆解RPC高性能本质,提出“对外REST求兼容、对内RPC求性能”的企业级分层架构实践。(239字)
289 8
|
2月前
|
人工智能 中间件 API
LangChain+Llama.cpp 本地模型与Agent工具调用
本文介绍如何用LangChain对接本地llama.cpp服务:通过`llama-server`启动Qwen量化模型,配置OpenAI兼容接口;安装LangChain生态包;实现基础对话与自定义工具Agent(如查天气、时间),全程离线运行,零依赖云端API,适合私有化AI原型开发。(239字)
293 3
|
3月前
|
弹性计算 人工智能 运维
阿里云轻量应用服务器指南:收费价格、适用场景、轻量实例及限制说明
阿里云轻量应用服务器(SAS)是面向开发者、学生及小微企业的轻量化云服务,开箱即用、操作极简。2026年全系标配200M峰值带宽+不限流量,预装WordPress、Docker、AI等24种镜像,38元起/年,分钟级部署,高性价比入门首选。阿里云轻量应用服务器官网:https://t.aliyun.com/U/dwftch
|
1月前
|
存储 Kubernetes Docker
01| 裸机部署 K8S:从零搭建生产可用集群
本文系统介绍Kubernetes(K8s)核心概念与实战部署:涵盖应用部署演进、容器编排原理、架构设计(Master/Node、Pod、Service等)、分层模型,并详解基于kubeadm的集群搭建全流程——含环境准备、Harbor私有仓库构建、cri-docker配置、镜像预拉取、初始化及Flannel网络插件安装,助力快速落地生产级K8s集群。(239字)
283 0
|
3天前
|
人工智能 自然语言处理 前端开发
Vue3 + Spring Boot + 百炼:AI 客服对话系统的全栈实战
10个客服每天处理800条咨询,平均响应5分钟,夜间完全无人值班——这是很多企业客服团队的真实困境。本文从实际项目出发,完整演示 Vue3 + Spring Boot + 阿里云百炼搭建 AI 智能客服系统的全流程:百炼平台配置 → 知识库构建 → DashScope SDK 流式对接 → 多轮上下文管理 → 人工转接 → 对话评价统计 → Vue3 对话组件 → 管理后台 → 进阶能力,最终 70% 问题秒级响应,夜间全覆盖,客户满意度从72%提升到93%。文中包含5个生产踩坑实录和完整的AI客服选型决策树。