我给 QQ 群写了一个直播平台:PrismLive 开发手记
一台 8G 内存的旧服务器,一个 Node.js 进程,一个单文件媒体服务。这是我给自己社群做的直播平台。
起因:为什么非要自己造轮子
事情的起点特别朴素——我们 QQ 群想搞点直播,比如一起看球、讲题、开个线上分享会。
一开始也试过公共平台。但很快就发现不对劲:开播要审核、画面里不能出现这不能出现那、观众还得下载 App、弹幕里混进一堆陌生人。在群里几百个熟人的私域场景里,这些限制既多余又烦人。
我就想:直播这件事,拆开来看其实没多复杂——一个人推流,一堆人看,中间飘几条弹幕。凭这三样,我为什么不自己搭一个?
说干就干。现在回头复盘,整个项目踩过的坑、做过的取舍,都浓缩在下面这几关里。
第一关:怎么把画面"送"出去
主播电脑上要有个软件把摄像头画面推出来,这活儿几乎只有一个标准答案——OBS(免费、强大、人手一份)。它通过一种叫 RTMP 的协议,把画面像"连了一根话筒线"一样,实时推送到服务器。
那服务器端谁来接这根线?这里就是我做的第一个重要决定:不自己写媒体服务器。
视频的转封装、切片、分发,是直播里最难啃的骨头,自己写等于重新发明轮子,还大概率写不过人家。所以我直接引进了 MediaMTX——一个只有十几兆的单文件程序,RTMP/RTSP/HLS 全支持,零配置就能跑。OBS 推给它,它帮我完成后面所有脏活累活。
于是链路的第一段就通了:
OBS 推流 ──RTMP──▶ MediaMTX ──转封装──▶ 观众浏览器
(话筒线) (专业接线员)
这条朴素的思路贯穿始终:媒体的事交给专业组件,业务逻辑自己写。剩下的,就都是我能掌控的 Node.js 代码了。
第二关:观众用什么姿势看
画面到了服务器,观众怎么拿?这里遇到直播领域最经典的抉择——HLS 还是 FLV?
用最直白的话解释这两个协议:
- HLS 像是"把直播切成一片片面包,观众一片片取"。好处是几乎所有浏览器都吃这一套,微信里也能播,还天生适合 CDN 加速;坏处是慢——端到端往往有 10 秒以上的延迟。
- FLV 像是"一根一直在流水的水管"。延迟能压到 3 秒以内,互动感极强;坏处是兼容性差,走代理隧道还可能断流。
小孩子才做选择,成年人……我两个都要。我把它做成了后台可切换的双引擎:默认 HLS 保底,需要低延迟互动就切 FLV。
更有意思的是自动回退这个细节:FLV 一旦播放出错,前端会悄悄降级回 HLS,而且整个会话只回退一次,不会反复横跳。还有个小判断——如果检测到观众是穿过隧道/代理来的,后端直接不返回 FLV 地址。为什么?因为 FLV 是长连接拉流,隧道转发必然出问题,与其让观众傻等,不如一开始就明确告诉他"这条路不通,走 HLS"。
连推流状态都是双保险:服务端每 5 秒同时探测 MediaMTX 和 SRS 两个引擎,哪个活跃都算"直播中",码率、观看人数、推流时长一起算好展示。
第三关:弹幕怎么才能不崩
直播的灵魂是弹幕。但弹幕也是被攻击的重灾区——刷屏、灌水、颜色注入。我做了三层防护,每一层都很轻:
- 单用户冷却:同一个人两条弹幕之间必须隔 0.8 秒,手速再快也没用;
- 全局限速:以 1 秒为窗口,每秒总弹幕量可配置上限,防止瞬间洪水;
- 速率统计:用一个固定 2048 长度的环形缓冲记录弹幕时间戳,像"汽车的里程表"一样 O(1) 算出每分钟弹幕数——时间再久,内存和计算量都不会无限膨胀。
弹幕传输用的是 Socket.IO,你可以理解成一个"全房间大喇叭":谁喊一嗓子,服务端立刻广播给所有人,不用观众反复刷新。
还有两个让我自己都挺得意的小心思:
- 颜色白名单:弹幕颜色只允许白/红/粉/紫/青/绿/黄/橙这 8 种。别小看这个限制——它从根上堵死了"塞任意颜色值注入样式"的漏洞,攻击者连门都摸不到。
- QQ 头像:观众填 QQ 号就能自动带出昵称和头像。为了这个接口不被刷爆,我加了 1 小时内存缓存 + 每 IP 每分钟限 10 次。
第四关:主播需要一个指挥台
直播进行时,主播/管理员需要的可不是普通观众页面,而是一个能"眼观六路"的中控后台:
- 实时看板:当前在线、峰值在线、今日观看、累计弹幕、每分钟弹幕速率、累计点赞。这些数字通过 Socket.IO 每 2 秒刷新一次,数字用等宽字体渲染,不会一跳一跳地晃眼睛;
- 推流状态卡:实时码率、推流时长、累计上行流量、媒体层读者数、HLS/FLV 两个引擎各自的状态灯——哪个引擎在跑一目了然;
- 链路诊断:每 15 秒自动探测各条分发线路(隧道、域名、端口)的延迟和 HTTP 状态。哪条路挂了,一眼就能看出来,不用抓瞎;
- 数据曲线:用 ECharts 画在线人数和弹幕趋势,还能一键导出 CSV;
- 黑名单:按昵称或 QQ 号拉黑,永久生效。
后台能实时看到"现在有几个人在看、画面码率多少、哪条链路不通",这种掌控感,是公共平台给不了的。
第五关:安全这根弦,松不得
自建服务被盯上是迟早的事,安全我从第一天就在做:
- 登录防爆破:10 分钟窗口内密码错 5 次,锁定 10 分钟。暴力破解基本没戏;
- 接口鉴权:后台所有接口(除了登录)都要带
Bearer令牌,令牌 24 小时过期、自动清理; - 推流密钥:随机生成、可重置。OBS 必须带对密钥才收流,否则画面根本进不来;
- 敏感词过滤:后台可配敏感词,命中即拦截;
- 默认密码提醒:后台默认密码
admin123,登录页明晃晃写着"请及时修改"。
说白了,这一整套就像给直播间配了个尽职的门卫:该拦的拦,该放的放,还时不时提醒你"门锁该换了"。
数据:一本随身的记账本
存储上,我做了一个事后被证明特别对的选择——直接用 Node 22.5+ 内置的 SQLite(node:sqlite)。
好处是惊人的:零原生编译依赖。这意味着 npm install 再也不会因为缺 C++ 编译链而在 Windows 上翻车。数据就是 data/ 下一个单文件,里面三张表:
settings:标题、公告、开关、敏感词、推流密钥、密码(加盐哈希)、引擎配置;blacklist:黑名单;stats:统计(今日观看、累计弹幕、峰值在线,按天重置)。
备份?拷走一个文件 + 导一下库,完事。对个人项目来说,这比什么分布式数据库都香。
好看,真的重要
技术上跑通只是及格线,长得丑没人愿意看。所以前端我也花了心思——原生 HTML/CSS/JS,零框架零构建,但视觉规格统一:
- 深蓝黑渐变背景(
#0b0f1a → #141a2e),品牌紫#7c5cff点缀,偶尔用青#22d3ee做数据色; - 玻璃拟态卡片(半透明背景 + 毛玻璃模糊 + 细边框);
- 深色模式、移动端横竖屏都适配。
哪怕是个"自己人用"的直播平台,打开第一眼也得像那么回事。

写在最后:几个小心得
回头看,PrismLive 代码量不大,但它教会我几件事:
- 别什么都自己写。把媒体交给 MediaMTX,把数据交给 SQLite,把精力花在"业务逻辑"这一亩三分地上,才是个人项目该有的姿势;
2. 细节即护城河。双引擎回退、环形缓冲限速、颜色白名单、隧道检测——每一个都只是几十行代码,但每一个都在真实场景里兜了底;
- 安全不是可选项。哪怕服务只给自己人用,防爆破、鉴权、敏感词这些也得从第一天就做,因为攻击者不会因为你"低调"就放过你。
一台 8G 内存的旧服务器,跑起一整套直播平台,稳稳当当。如果你也想给某个小圈子搭一套自己的直播,希望这篇手记能帮你少踩几个坑。
—— 欢迎交流,也欢迎去试试推一条流过来,直播间见。
评论交流
欢迎留下你的想法