ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

赛事直播推流架构设计与实践:从SRT推流到CDN分发全链路解析

赛事直播推流架构设计与实践:从SRT推流到CDN分发全链路解析 做了大半年星逐赛事直播间的推流架构从最开始几个人在办公室里拿OBS推流试播到后来支撑多机位、多路解说、全国观众实时观看整个链路反复拆过好几遍也踩了不少坑。赛事直播和普通秀场、带货直播最大的区别在于观众容忍度极低画质不能糊声音不能断延迟不能高而且并发峰值来得特别陡——比赛一开场流量是瞬间涌进来的根本不给时间慢慢扩容。这篇文章我把星逐赛事直播间这套推流架构的完整设计和实践过程整理出来覆盖推流端、服务端、分发层三层链路包括协议选型、参数配置、服务端转码录制、接口压测、带宽压测、边缘分发、监控容灾这些环节。适合正在做直播系统、赛事转播、低延迟直播平台的开发者、运维和架构师参考内容偏向实战很多参数和配置都是我实际验证过的可以直接抄作业但前提是理解背后的计算逻辑不是盲目照搬。1. 先搞清楚赛事直播到底需要什么1.1 星逐赛事直播间的真实场景星逐赛事直播间早期定位就是电子竞技赛事和线下体育赛事的实时转播场景比普通直播复杂得多。首先现场至少三路以上的摄像机位每一路都是独立音视频流其次有导播台负责画面切换有解说员的声音需要混入最后观众端的播放体验要求非常高不能出现长时间黑屏、音画不同步、花屏这些问题。我们最开始犯过一个经典错误直接套用视频号、抖音那种单主播推流方案一台电脑接摄像头OBS推到云厂商的直播服务完事。结果真正办第一场线上赛事时问题全暴露了——机位切换有黑场解说声音和画面错位公网推流偶发丢包导致观众端卡成PPT。后来才意识到赛事直播必须有一条完整可控的技术链路而不是靠单点工具拼凑。这里先给一个总体架构轮廓后面每个模块展开细讲推流端摄像机信号进入导播台导播台输出PGM节目输出信号经编码器或推流软件编码后通过SRT/RTMP协议推到服务端。服务端负责收流、转封装、转码、录制、鉴权、接口管理承担核心的业务逻辑和数据加工。分发层把服务端处理好的流推到CDN边缘节点观众从最近的节点拉流中间涉及调度、缓存、回源。三层链路的核心思路是“推流端少干活、服务端兜底、分发层离用户近”。推流端只负责把画面稳定送出去服务端做流处理和业务逻辑分发层解决大规模并发观看问题。这样每一层的职责边界清晰出现问题时能快速定位到底卡在哪一层。1.2 三层的职责边界为什么要这么分很多刚接触直播架构的人会问推流端直接推到CDN不行吗为什么非要中间架一层自己的服务端这个问题的答案直接决定了整个架构的设计方向。如果推流端直接推CDN确实省事但代价是几乎失去所有控制权。赛事直播有几个硬性需求是CDN直推解决不了的多路流的汇聚和切换、录制存档、实时转码出多码率、对推流内容做鉴权审核、以及推流链路的主动监控。这些业务逻辑都得有一个自己的服务端来做。我们当时的服务端部署在云上承担的任务包括接收推流端的SRT流、转封装成FLV和HLS、按照预设规格转码出多码率、把原始流录制为TS文件存档、同时对外提供拉流地址的签发和鉴权接口。CDN只负责最外层的分发和加速回源到我们的服务端拉流。这个结构的好处是即使CDN出问题我们也能快速切回源站直出不至于全盘瘫痪。分发层单独拎出来是因为观看端的规模和推流端完全不是一个量级。推流端的路数有限但观众可能是几十万甚至上百万。如果所有观众都直接从源站拉流源站带宽瞬间被打满。CDN边缘节点的作用就是各区域形成缓存和就近分发把回源压力降到最低。这点后面在分发层章节还会详细算带宽账。1.3 协议选型不能拍脑袋协议选型是整个架构里最不能糊弄的环节选错了后期改动成本极高。我们的推流协议最终选择了SRT为主、RTMP为辅分发协议选择了HTTP-FLV为首选、LL-HLS为备选WebRTC用于内部低延迟预览。下面把这个选型逻辑拆开说明。先看推流端。RTMP是老牌协议基于TCP兼容性极好OBS、FFmpeg原生支持很多云直播服务的接入也都支持RTMP。但RTMP在公网环境下有个致命的弱点TCP丢包重传一旦网络抖动延迟会越拉越大恢复需要时间画面容易卡顿。赛事直播现场经常在体育馆、户外场地公网链路质量不可控用RTMP推流我并不放心。SRT协议基于UDT本质上是UDP之上做了可靠传输和重传控制。它的核心优势是抗丢包能力强在20%甚至更高丢包率的环境下通过ARQ自动重传请求机制还能保持流畅传输同时可以通过配置延迟缓冲来对抗网络抖动。实测下来SRT在跨省公网链路上的稳定性比RTMP好很多。代价是需要推流端和接收端都支持SRT好在OBS新版原生支持SRT协议FFmpeg也支持libsrt生态已经成熟。分发侧HTTP-FLV延迟能做到1到3秒兼容性也好主流播放器都有成熟方案我们用它作为默认分发协议。LL-HLS低延迟HLS把切片做得更小、更频繁端到端延迟能到3到5秒适合需要回看和拖动进度条的场景。WebRTC延迟能压到500毫秒以内但服务端和播放端都要上SFU类组件成本较高我们用它做内部分析师观看的低延迟流不对公众开放。说白了协议选型没有“最好”只有“最合适”。结合赛事直播对实时性、稳定性和兼容性的要求SRTHTTP-FLV这条组合是最务实的答案。2. 推流端从摄像机到服务器的最后一米2.1 采集编码这块怎么定参数推流端是整个链路的数据源头源头要是脏了后面无论做多少优化都补不回来。我们现场的设备链路是摄像机SDI信号接入导播台ATEM Mini Pro导播台的PGM输出通过HDMI接采集卡采集卡进入推流电脑由OBS或FFmpeg完成编码和推流。这里我要特别强调采集设备选型的问题。很多人觉得用USB采集卡就行但赛事直播现场设备多、电磁干扰大劣质USB采集卡容易出现掉帧、信号不稳定甚至采集不到画面。我们最后用的是带SDI接口的硬件采集卡虽然贵一些但稳定性和画质完全值得。如果你预算有限至少选Magewell这类口碑好的牌子不要贪便宜买几十块的卡。编码参数上最关键的是分辨率、码率、帧率、编码器四件套。我们采用1080p、50fps、主码率6Mbps、x264编码器的组合。这样设置的原因是赛事画面运动剧烈帧率太低了画面不流畅50fps比25fps更适合比赛转播而6Mbps在高动态画面下1080p的H.264编码能保住画质细节不会出现大面积马赛克。码率不是拍脑袋定的可以简单算一下公式码率(Mbps) 分辨率宽度 × 分辨率高度 × 帧率 × 复杂度系数 / 压缩率。经验上1080p50的H.264高画质大约需要6到8Mbps这个值可以根据画面复杂度调整体育赛事建议取中高值。码率设低了剧烈运动画面糊成一团设太高了推流端网络压力大公网推流容易卡浪费带宽。2.2 FFmpeg推流参数具体怎么配虽然OBS图形界面很方便但在自动化和精细控制上FFmpeg依然是推流端最强的工具。星逐赛事直播间的自动化推流脚本就是用FFmpeg实现的它从导播台的采集卡读取画面加上字幕和时间戳再通过SRT推流到服务端。这里给出一段我们实际使用的推流命令里面的参数每一行都有讲究ffmpeg -f lavfi -i anullsrcchannel_layoutstereo:sample_rate48000 \ -f dshow -video_size 1920x1080 -framerate 50 -pixel_format yuyv422 \ -i video采集卡设备名 \ -c:v libx264 -preset veryfast -tune zerolatency -b:v 6M \ -maxrate 6M -bufsize 12M \ -g 100 -keyint_min 100 -sc_threshold 0 \ -c:a aac -b:a 192k -ar 48000 -ac 2 \ -f mpegts -flush_packets 1 \ srt://push.starzu.example.com:9000?streamid#!::rlive/starzu_main,mpublishlatency120maxbw50M逐个解释关键参数-preset veryfast编码预设值越快的预设CPU占用越低但压缩率也越低。赛事直播不能因为编码把机器CPU占满否则掉帧选veryfast是平衡点。-tune zerolatency禁用编码器的延迟优化缓冲让画面尽可能快地进入网络传输对低延迟推流至关重要。-g 100设置GOP关键帧间隔为100帧即2秒一个关键帧50fps下。这个值很关键关键帧间隔太大观众切换清晰度时会等很久才能出画面太小则码率波动大。-sc_threshold 0关闭场景切换检测。否则在画面切换、快速运动时编码器会自适应插入关键帧导致码率突然暴涨容易引发网络拥塞。-flush_packets 1强制每个TS包立即刷出缓冲区减少网络层延迟。SRT推流地址里的参数也有讲究latency120是延迟缓冲区大小毫秒太大会牺牲延迟太小则抗抖动能力差我们试下来120毫秒是公网推流的甜点值maxbw50M是最大带宽限制防止推流端在带宽充足时无限抢占带宽影响现场其他业务。2.3 SRT和RTMP到底怎么选这个问题被问太多次了。虽然前面提过但这里展开讲讲为什么我坚定选择SRT作为星逐赛事的主推流协议。RTMP的问题不在协议本身的设计而在于它依赖TCP传输。TCP为了保证数据完整性遇到丢包会不断重传重传期间的延迟会迅速累积。举个例子现场网络抖动时某一段数据丢了TCP会阻塞等待重传后续数据无法发送播放端的缓冲时间就会不断拉长表现出来就是延迟越来越大观众看到的画面比实际滞后十几秒比赛都开始了群里已经有人通过其他平台剧透了。SRT则把在丢包环境中保持低延迟作为设计目标。它的机制是接收端检测到丢包后会通过ACK/NACK消息告诉发送端只重传丢失的那部分数据发送端调整发送策略而不是像TCP那样无条件重传全部阻塞。同时SRT可以设置接收缓冲把网络抖动造成的到达时间差异缓冲掉保证上层的码流稳定输出。实际测试数据在10%随机丢包环境下RTMP推流丢帧率达到8%延迟快速恶化到5秒以上SRT在同样条件下丢帧率低于0.5%延迟可以稳定控制在1.5秒以内包含编码和缓冲。这个差距对赛事直播来说就是能不能正常观看的区别。所以如果您的推流端网络条件一般比如从体育馆、户外现场推流我强烈建议直接考虑SRT不要走RTMP否则上线后问题会接踵而来。2.4 多机位切换与解说混音的落地做法赛事直播的机位切换在导播台完成但导播台的输出和观众看到的画面不完全一致还需要加上比分条、广告贴片、解说混音这些逻辑我们放在推流端解决。导播台PGM输出接入推流电脑后OBS里建立多场景主画面场景、比分条叠加层、广告插播层、结束画面层。解说员的音频通过USB声卡进入电脑在OBS音频混合器中和现场音混在一起设定好音量调整规则。这样推流出去的流就是一个完整的“直播节目信号”服务端只做处理不再参与编导。有一个容易被忽略的细节解说音的延迟匹配。现场麦克风采集到的声音如果直接混入和画面中的嘴型可能对不上因为导播台到采集卡再到编码器视频路径本身有几百毫秒延迟。我们在OBS音频高级设置里给解说音加了约300毫秒的延迟和画面同步。具体数值需要根据现场实测调整方法是在画面中拍手录屏后用剪辑软件看声波峰值和画面落差的帧数差换算成毫秒。混音时的音频参数也统一了48kHz采样率、16bit、双声道AAC编码码率192kbps。这里要注意音视频流里的采样率必须全局一致否则服务端在转封装时可能会出现音画不同步后面故障排查章节会再讲这个坑。3. 服务端收流、转码、录制与压测3.1 开源自建还是商业方案服务端是整个架构的中枢这块的选型我们纠结了最久。商业直播服务如云直播平台接入简单、稳定性有保障但对自定义转码规格、录制格式、鉴权方式都有严格限制而且按带宽和转码时长计费长期成本不可控。我们最后选择了开源自建用SRS配合ZLMediaKit组成服务端集群。选择自建的原因有三个一是要求完全控制转码规格比赛需要多码率输出1080p主码流、720p中码流、360p低码流云服务对自定义转码参数支持不够灵活二是录制存档需要保留原始TS流商业平台一般只提供转码后的MP4原始流的精细度和灵活性不够三是鉴权和防拉流盗链规则需要和自研业务系统打通自建可以完全按需求设计方案。SRS是国产开源流媒体服务器支持RTMP、SRT、WebRTC等多种协议性能很强单机可以支撑数万路并发。ZLMediaKit则是一个更通用的流媒体服务框架支持GB28181、RTSP、SRT、HTTP-FLV等协议。我们让SRS主力承担SRT收流和HTTP-FLV分发ZLMediaKit承担RTSP/RTMP的内部流转和录制任务两个组件通过流间转发协同工作。3.2 SRS/ZLMediaKit的配置要点SRS作为主要收流和分发节点配置文件里几个关键参数需要注意。以下是我们线上SRS的vhost配置片段vhost starzu_live { tcp_nodelay on; min_latency on; srt { enabled on; latency 120; maxbw 50000000; } play { gop_cache on; queue_length 10; mw_latency 100; } http_flv { enabled on; mount [vhost]/[app]/[stream].flv; hstrs on; } hls { enabled on; hls_path /data/hls; hls_fragment 2; hls_window 60; hls_cleanup on; hls_dispose 62; } }gop_cache on是开启GOP缓存让新进用户能快速拉到最近的关键帧秒开率大幅提升。queue_length 10是播放队列缓冲包数量设太高会增延迟太低容易因网络抖动卡顿。hls_fragment 2是HLS切片时长设为2秒这是低延迟HLS的关键切片太大会增高延迟太小会增加文件碎片压力。ZLMediaKit我们主要用于录制和内部RTSP流转。录制采用MP4分段录制每2小时一个文件方便回看和归档。分段录制时要注意一个坑切片边界要和服务端的GOP对齐也就是说录制文件的起始必须是一个关键帧。如果切片起始不是关键帧播放时开头必然花屏或者黑屏。我们通过配置recordRtmpAsMp4、recordHlsAsMp4并同时保证录制启动时的关键帧对齐解决这个问题。服务端还有一项重要工作是转码。赛事需要多码率输出每路主码流进来后用FFmpeg拉流转码输出两个清晰度较低的流命令大致如下ffmpeg -i http://127.0.0.1:8080/live/starzu_main.flv \ -c:v libx264 -preset veryfast -b:v 2M -maxrate 2M -bufsize 4M \ -vf scale1280:720 -g 100 -keyint_min 100 \ -c:a copy -f flv rtmp://127.0.0.1:1935/live/starzu_mid注意转码流的GOP要和主码流保持一致都为2秒一个关键帧这个是确保播放端在切换码率时能够无缝衔接的关键。如果GOP不一致切换清晰度时播放器必须等待下一个关键帧等待时间长短不齐观众的体验会非常撕裂。3.3 服务端接口设计与全链路压测服务端不只是处理流还要面向业务系统提供接口。星逐赛事的服务端接口主要包括推流地址签发、拉流地址签发、流状态查询、录制任务管理、观众统计。接口全部走HTTPS鉴权采用JWT接口签名双重校验。推流地址签发逻辑导播系统请求服务端获取推流地址服务端校验权限后生成带鉴权参数的SRT地址推流端应使用该地址进行推流服务端在收流时校验地址合法性不合法的流直接拒绝。拉流地址签发逻辑观众端不直接接触CDN地址而是请求业务后端换取一个带时效的播放凭证播放器拿凭证去边缘节点拉流边缘节点向服务端验证凭证有效性。有效期通常设30分钟过期后播放器重新请求防止地址被恶意扩散。接口上线前必须做压测这里我说说我们压测时用到的工具和方法。服务端接口压测用JMeter配置线程组模拟2000个并发用户同时请求拉流地址签发接口观察服务端的QPS响应时间和错误率。我们当时把接口峰值QPS压到了3000服务端CPU和内存依然在合理范围内给线上留出充足余量。很多人在做直播系统时只测接口不测流链路这是很大的疏漏。流链路的压测我们采用模拟推流的方式用FFmpeg生成一路带时间戳的测试视频流循环推送到服务端再用多台拉流客户端同时播放观察播放端的实际首帧时间、卡顿次数和延迟漂移。压测期间还有一个重要工具是iperf/jperf。它能直接测试两台机器之间的TCP/UDP带宽和丢包率帮助定位链路瓶颈。我们在服务端和边缘节点之间、服务端和推流端之间都会跑iperf命令类似# 服务端监听 iperf3 -s -p 5201 # 推流端发起测试 iperf3 -c push.starzu.example.com -p 5201 -u -b 50M -t 30-u -b 50M表示UDP模式、目标带宽50Mbps能模拟推流时的网络压力。实测发现某个边缘节点回源带宽不足就是靠iperf压出来的——TCP模式下带宽能达到80Mbps但UDP模式下一旦超过30Mbps就开始丢包加了SRT协议后问题被放大最后换了更高带宽的节点才解决。3.4 网络带宽压测别等上线才做带宽压测这块我单独拿出来说是因为太多直播事故的根源就是带宽评估失误。很多人上线前只测功能不测带宽结果比赛当天观众一多服务器带宽瞬间被打满服务端和CDN之间回源链路拥塞视频全部卡死。带宽怎么算举个例子说明假设一场比赛高峰期20万观众同时在线观看主流码率2Mbps那么理论带宽需求是20万×2Mbps400Gbps。这个量级的带宽任何一家单机房都不可能扛住必须靠CDN边缘节点分摊。这也就是为什么分发层一定要上CDN而不是让所有观众都来源站拉流。源站带宽的规划主要是给CDN回源和边远节点兜底用的。我们的源站带宽按观众并发量的5%到10%估算20万观众、2Mbps码流、5%的观众同时回源其他都在边缘节点命中缓存——20万×5%×2Mbps200Gbps还是很大。再分摊到多个源站节点每个源站机房带宽可以控制在40到50Gbps相对可控。更精准的做法是在上线前做带宽压测用多台压测机从不同地区同时拉流逐步增大并发数观察源站的出方向带宽、CPU、内存、和回源成功率。我们一般压到预估峰值的1.2倍保证留有余量。这里有个经验每个边缘节点的回源连接数也是有上限的一条2Mbps的流如果回源节点并发连接数会占用很多资源所以控制回源比例非常关键。CDN厂商提供的回源配置里通常有“回源比例”的设置正常情况下让边缘节点命中缓存即可只有缓存未命中才回源这样回源带宽远低于理论峰值。4. 分发层让观众离得再近一点4.1 边缘节点与调度策略分发层的本质是“把数据尽量推到离用户最近的地方”。星逐赛事的观众分布在全国各地不可能让所有观众都通过公网链路去源站拉流那样延迟高、失败率高、带宽成本也无法承受。CDN边缘节点就是一个一个前置缓存点观众从最近的节点拉流节点回源站拉取一次然后缓存给这一片区域的观众共享。CDN调度的核心是DNS调度和HTTP重定向调度。DNS调度是根据用户请求的DNS服务器IP和地理位置返回最近的边缘节点IPHTTP重定向则是在播流URL里附加token播放器请求某个调度域名后服务端返回302跳转到实际边缘节点的地址。星逐赛事的拉流URL格式大致是http://play.starzu.example.com/live/starzu_main.flv?tokenxxxexpire1710000000播放器会先请求play.starzu.example.comCDN的GSLB全局负载均衡根据用户来源解析到最近的边缘节点然后边缘节点收到带鉴权参数的FLV拉流请求后再向源站回源拉取。回源策略我们设置的是“首次拉流回源后续命中缓存”同一边缘节点相同流只有第一个用户会触发回源其余用户直接吃缓存边缘节点连接的压力大幅降低。4.2 三种分发协议延迟对比分发协议的选择直接影响观众的观看延迟而不同场景对延迟的容忍度又不一样。我把星逐赛事实践过的三种主要分发协议做个对比方便不同需求的场景直接参考协议端到端延迟兼容性适用场景我们的用途HTTP-FLV1~3秒需FLV解析移动端需插件或原生SDK赛事直播主推流观众端默认协议LL-HLS3~5秒支持HLS的播放器基本可用需要回看的准直播场景备用/回看WebRTC0.2~0.5秒需WebRTC SDK极致低延迟内部预览内部分析师信号延迟差异来源于协议设计的区别。HTTP-FLV把音视频数据封装成FLV格式通过HTTP分块传输播放器可以边下载边播放不需要像普通HLS那样等切片文件生成后再拉取所以延迟低很多。LL-HLS改进了HLS把切片切成2秒甚至更小的段并且支持播放器在段未完全生成时就开始请求比普通HLS压缩了至少一半延迟。WebRTC则走的是UDP传输配合SRTP加密和FEC前向纠错延迟最低但对网络质量和服务器处理能力要求也高。延迟是直播的生命线尤其是赛事直播——观众可能在一个群里一边看直播一边讨论比分如果有人看到了结果弹幕刷在群里延迟高的观众就被剧透了体验直接崩。所以我们的策略是默认走HTTP-FLV同时根据播放器兼容性自动降级到LL-HLS。实测HTTP-FLV的端到端延迟可以稳定在2秒左右LL-HLS在4秒左右观众基本无明显感知差异。4.3 回源链路与缓存控制分发层还有一个常被忽略但直接影响成本和稳定性的问题回源策略和缓存控制。回源链路的核心目标是减少回源请求数量和带宽压力。我们做了三个层面的优化第一GOP缓存。边缘节点缓存一整个GOP的数据新观众接入时可以从GOP起点开始拉流这样能保证秒开同时减少回源请求。CDN节点上如果已经缓存了最近2秒的GOP数据新用户就直接从缓存开始播不用等源站回源。第二回源预热。大型赛事开始前10分钟我们会对所有边缘节点做拉流预热让每个节点提前从源站拉取一次直播流缓存下来。比赛一开始观众涌入时边缘节点直接命中缓存不会出现“回源风暴”——所有节点同时回源把源站带宽打爆。第三过期与回退。直播流的缓存和普通HTTP文件不同它是持续生成的边缘节点需要不断从源站拉取新的数据。我们设置边缘节点向源站回源时带一个过期判断参数源站检测到流不活跃时返回404边缘节点则停止回源并提示播放器重试其他节点。这个机制能有效避免赛事结束或推流中断后边缘节点还在不断回源拉死链浪费资源。还有一点要提醒CDN节点的缓存不是越多越好。直播流是实时数据缓存太深会导致观众看到的画面比实际晚很多延迟剧增。我们要求CDN节点只缓存最近1到2个GOP的数据约2到4秒后续数据实时回源拉取。这个参数在CDN控制台的直播流缓存配置项里可以设置不同厂商叫法不同位置可能不一样但原理相同。5. 全链路监控与容灾排障实录5.1 质量指标怎么采才准确监控是直播系统的眼睛没有持续可靠的全链路监控出了问题只能靠观众在群里喊“卡了卡了”。星逐赛事直播间上线前我们建立了一套全链路质量监控体系覆盖推流端、服务端、分发层三个环节。推流端监控指标包括推流码率、帧率、丢包率、CPU占用、内存占用以及SRT连接的延迟和重传率。推流电脑上跑一个Agent每5秒上报一次这些数据到监控平台超过阈值自动告警。SRT的延迟和重传率尤为关键它们能反映公网链路质量重传率突然上升往往意味着带宽即将不够。服务端监控指标包括收流状态、并发连接数、回源带宽、转码CPU占用、录制文件完整性、接口QPS和错误率。SRS和ZLMediaKit都提供HTTP API查询流状态和连接信息我们写了个采集脚本每10秒拉一次存入时序数据库配合Grafana做可视化。分发层监控指标包括边缘节点在线人数、拉流成功率、首帧时间、卡顿率播放器上报、回源比例、各节点告警。这部分数据主要来自播放器SDK的上报播放器每30秒上报一次播放统计包括缓冲事件次数、平均码率、播放延迟等这样才能掌握观众端的真实体验。播放端的体验数据和推流端的网络数据要打通看。比如某省观众卡顿率突然升高去看该省边缘节点的回源成功率再看源站是否有丢包基本就能定位问题在哪个环节。从推流到播放的完整链路形成了直播拓扑可视化图异常节点一目了然。5.2 常见故障与排查经验汇总排障环节是整个项目中最琐碎的但也是最有价值的。下面把我在星逐赛事直播间的实际排障经历和对应排查方法整理成速查表篇幅有限不展开每一个场景但原理和关键点都标出来故障现象常见原因排查方法与解决方向观众端花屏/马赛克推流端码率不足、编码质量差、网络丢包严重查看推流端码率和重传率降低分辨率提高码率或换推流链路首帧时间过长播放器拉流时未命中关键帧、CDN缓存未预热、边缘节点过远开启GOP缓存、赛前CDN预热、优化调度策略音画不同步推流端音频参数不一致、服务端转码时音视频时间戳漂移统一音频采样率检查时间戳基准给解说音加延迟补偿服务端并发过高宕机回源风暴、连接未释放、接口慢查询限制单IP连接数、优化连接池、预热边缘节点、接口做限流录制文件无法播放录制切片起始不是关键帧、TS封装损坏配置录制关键帧对齐转封装时重新指定GOP起点CDN回源失败源站带宽打满、鉴权token过期、边缘节点白名单未放开扩容源站带宽、检查回源鉴权参数、更新白名单这里挑一个最典型的坑详细展开——花屏问题。第一场赛事时观众端大面积反馈花屏排查后发现根因在推流端导播切换机位时编码器检测到画面大幅变化触发了场景切换自适应插入了一个新的关键帧但此时网络带宽还没跟上导致关键帧数据不完整。播放端收到的关键帧是残缺的整个GOP解码出来都是花屏。解决方法是sc_threshold 0关闭场景切换让GOP严格按照固定间隔生成。这个参数在OBS里对应的是“关键帧间隔”设置很多教程都建议设2秒但很少人意识到还要在FFmpeg里显式指定sc_threshold 0否则GOP缓存会失效首帧秒开和花屏问题都会冒出来。再比如音画不同步的排查最初我以为是播放器问题后来发现是推流端音频用了44.1kHz采样率而视频的时间戳基准是90kHz时钟两者换算对不上导致每几分钟音频就比画面慢几百毫秒。整个链路的音频采样率统一改成48kHz后问题彻底消失。这个坑如果你只在OBS图形界面上操作是永远碰不到的因为OBS会自动帮你处理好。5.3 容灾方案主备切换与降级策略容灾是直播系统上线的最后一道防线直接决定比赛出问题时是不是事故。星逐赛事直播间的容灾方案从三层分别设计确保任何单点故障都不会导致直播中断。推流端容灾现场采用双机推流模式主推流机和备用推流机同时从导播台获取相同信号都通过SRT推到服务端但不同时转发到分发层。主推流机正常时备用流只录制不转发一旦主推流链路断开监控系统自动把备用流切换为转发状态观众延迟恢复时间控制在5秒以内。比赛开场前一定要测试这个切换流程最好模拟一次主推流断网。服务端容灾SRS集群部署两个节点主节点和备节点实时同步流状态。正常时流量全部走主节点备节点空闲待命主节点故障时DNS和负载均衡器自动把新请求切到备节点。这里要注意SRT推流端需要配置服务端地址的可重试机制OBS和FFmpeg都有重连选项建议把重连间隔设3秒最多重试10次。分发层容灾CDN要选择支持多线多节点的厂商开通至少两个CDN服务商作为互备。正常时70%流量给主CDN30%给备CDN主CDN故障时全量切到备CDN。切换操作要提前写成脚本一键封禁主CDN域名的解析并修改播放器配置域名对应到备CDN。这事看起来简单但真正灾害发生时多复制一个域名配置的时间都可能造成大规模断流。最后一个降级策略如果源站带宽或服务端CPU达到危险水位需要快速启用降级方案——自动把观众拉流切到低码率转码流例如把2Mbps的720p流降为1Mbps的360p流确保所有观众还能看到视频虽然画质有损但直播没有中断。降级触发条件和恢复机制我们在监控平台里提前配置好由告警系统自动执行不需要人工干预。写在最后的几点实际操作体会整个星逐赛事直播间推流架构从设计、开发、压测到正式上线走了不少弯路也积累了一些很有用的经验。第一架构设计一定要先做压测再上线尤其是带宽和接口压测。上线前我们压测发现源站带宽缺口超过40%及时扩容避免了赛事当天的大事故。第二推流端要多做自动化不要依赖人工操作。第三全链路质量监控比任何优化都重要——没有数据一切排查都是瞎猜。如果你也想搭一套类似的赛事直播系统我的建议是先从小规模开始把推流端、服务端、分发层的链路走通确认每一层的监控数据都齐全了再逐渐扩大规模。不要一上来就追求大而全的架构先把核心链路的稳定性和可观测性做好后续扩并发就是重复加节点和带宽的事。最后分享一个小技巧上线前一定要安排一次“全链路断网演练”。模拟推流端网络断开、服务端宕机、CDN故障三个场景把所有容灾切换逻辑跑一遍时间控制在5分钟以内。这件事做一次胜过现场出问题时的十次加班。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进