ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

广电视频服务器安可迁移:开源模块选型与编译部署实战

广电视频服务器安可迁移:开源模块选型与编译部署实战 广电行业做视频服务器的同学最近一年听到最多的一个词应该就是“安可”。落到实际工作上就是原来跑得很顺的转码服务器、收录服务器、流媒体分发服务器都开始要考虑迁移到一套约束完全不同的国产化软硬件环境里。刚开始你可能觉得“不就是Linux换Linux、CPU换CPU”真上手以后才知道坑全在细节里指令集不兼容、软件包没有、编译过不去、跑起来性能差一大截。而开源模块几乎成了唯一的出路因为你不可能从零自研整套信号处理栈。这篇文章我把自己在广电视频服务器适配安可系统的思路、模块选型和部署过程完整写出来。既面向负责系统选型的也面向一线动手编译部署的。内容里不会出现那种“这个模块很火所以你也用”的废话只讲我实际验证过、压过、跑过线上业务的模块以及每个模块在安可环境下会踩的坑。如果你正准备把视频服务器往安可环境迁移这篇文章可以直接拿来当参考清单。1. 先搞清楚安可环境下的广电视频服务器到底差在哪1.1 视频服务器的典型职责很多人一提广电视频服务器就以为是“一台跑流媒体的Linux机器”其实广电体系里的视频服务器身兼数职至少要覆盖这几类核心能力信号采集与收录从卫星、有线网、SDI等来源接入音视频信号按频道、按时间段录制生成素材文件。转码与压缩把采集到的高码率源信号转成适合播出、存储或分发的格式常见编码是H.264/H.265音频是AAC或MPEG Audio。封装与切片把转码后的流封装成MP4、TS、FLV等格式再按HLS/DASH协议切成小分片方便CDN和终端播放器拉流。协议分发支撑RTMP、HTTP-FLV、HLS、DASH甚至WebRTC等多种播出协议对接不同的终端和播出平台。播控与调度在内部做节目单管理、素材调度、多路并发控制。一句话概括视频服务器是一条“信号进、内容出”的流水线。迁移到安可环境不是把某一个软件装进去就完事而是整条流水线里的每个齿轮都要能转起来。1.2 安可给技术层面带来的三个真实差异我在实际项目里体会到安可系统对视频服务器研发的影响技术层面可以归纳成三点第一CPU指令集变了。老系统里很多优化是围绕x86指令集做的比如使用AVX、SSE的汇编优化库。换到新的国产化CPU平台上支持的可能是ARM指令集或其它架构过去那种“直接拿二进制就能跑”的做法基本失效。编译时汇编器不识别、运行时指令不支持这两类问题几乎天天遇到。第二基础软件生态变了。安可系统通常采用特定的操作系统底座很多常见的apt/yum软件源里根本没有现成的包。FFmpeg、Nginx、OpenSSL这些软件想用基本都得走源码编译。依赖关系一环套一环有时候一个库编译失败后面全卡住。第三硬件加速链路变了。老平台通常依赖Intel Quick Sync或者NVIDIA显卡做硬件转码。国产化平台上的硬件编解码能力也存在但对应的驱动、接口和用户态库跟老平台不完全一致。软件层面的转码方案必须提上日程并且要针对新平台的NEON/SIMD指令做适配否则一个4K频点的转码任务就把CPU吃满。理解了这三个差异你才知道选型时该看什么。不是谁的Star多就选谁而是谁能在这个新环境里顺利编译、稳定运行、性能达标谁才是能用的模块。2. 选型逻辑不要上来挑模块先把链路画出来2.1 一条完整的视频处理链路我第一次迁移时犯过一个错误上来就在GitHub上翻开源项目看到功能看起来齐全的就准备用。结果方案东拼西凑模块之间协议对不上、数据格式不兼容返工成本非常高。正确做法是先画链路。一条典型的广电视频服务链路按顺序分为四段接入段拉流、推流、SDI采集、文件导入统一转成内部原始流格式。处理段转码、缩放、添加台标、字幕混入、录制、抽帧。封装切片段按目标协议重封装生成分片、索引文件比如HLS的m3u8tsDASH的mpdmp4。分发输出段对外提供RTMP、HTTP-FLV、HLS、WebRTC访问做鉴权、限制并发、内容缓存。画完这条链路以后每个“节点”缺什么模块就很清楚了。比如接入段需要支持RTSP/RTMP拉流协议处理段需要FFmpeg和x264/x265库切片段可以是FFmpeg内部能力分发段需要SRS或ZLMediaKit这类服务。2.2 评估开源模块的三个硬指标链路画完再去给每个节点找模块评估标准只有三个有没有人持续维护要看最近一年有没有提交社区是否活跃。视频协议更新快尤其WebRTC、GB28181这些方向一个停更多年的模块在安可环境下出了问题没人帮你解决。能不能在目标架构上编译通过这点最实际。有的模块对x86的汇编优化做了强依赖在ARM平台上编译时会挂。如果模块官方已经出了aarch64的release包兼容性风险会小很多。依赖是否可控有的开源模块看起来功能强大但一拉依赖就是几十个库有些库还要求特定版本这种模块在安可环境下很可能变成时间黑洞。优先选那种依赖清单短、编译方式清晰的模块。我认识的同行里有人因为贪图功能丰富选了一款带过多依赖的流媒体平台最后光解决编译链就花了两周。这个教训挺深刻功能可以慢慢补编译不过去就是零。3. 值得收藏的开源模块名单与适配细节3.1 转码引擎FFmpeg 及配套编解码库点名模块第一名没有任何争议就是FFmpeg。它在视频处理领域的地位相当于文本处理界的标准工具解封装、转封装、解码、编码、滤波、切片、推流样样都能干。安可环境下FFmpeg承担的工作通常有三个信号录制、转码压缩、HLS切片。FFmpeg真正让人放心的一点是它对CPU架构的适应能力。它同时支持x86、ARM、MIPS等多种架构而且在ARM平台上有针对NEON指令集的优化代码。这意味着在主流国产化CPU平台上只要编译时把相关选项打开FFmpeg通常能正常工作。但在安可环境下FFmpeg不是“拿个二进制就能落地”的必须走一次源码编译并且要特别留意编解码库的取舍。我建议的最小编译方案是FFmpeg主体 x264 x265 fdk-aac。其中x264负责H.264编码x265负责H.265编码fdk-aac负责AAC音频编码。这三个库在广电业务里覆盖了绝大多数转码需求。编译FFmpeg的典型配置如下./configure --prefix/usr/local/ffmpeg \ --enable-gpl \ --enable-version3 \ --enable-libx264 \ --enable-libx265 \ --enable-libfdk-aac \ --enable-nonfree \ --enable-pthreads \ --enable-avfilter编译顺序有讲究先编译x264、x265、fdk-aac再编译FFmpeg本身否则configure阶段找不到对应库。在ARM架构平台编译时我会额外留一个心眼如果目标CPU的指令集支持程度不明确先不要把NEON优化选项强制打开用默认的自动检测。等编译通过、功能验证完再单独做一轮优化测试。提示FFmpeg的configure默认会自动检测CPU特性。遇到“asm”相关的编译错误时先排查是不是汇编器版本太老再考虑关闭特定指令集优化不要一上来就全关那样性能损耗很大。3.2 流媒体服务SRS、ZLMediaKit、Nginx-RTMP流媒体分发是广电视频服务器的核心出口。目前开源社区里真正经过大规模生产环境验证的主要就是SRS和ZLMediaKit另外Nginx-RTMP模块在老项目中出镜率也很高。我把它们放在一起对比。SRS是音频视频直播服务器定位非常聚焦直播分发。它支持RTMP、HTTP-FLV、HLS、WebRTC配置简单性能高。我在实际测试中用SRS转发1080p直播流单机支撑几千路播放没什么压力。而且SRS本身是C写的依赖少编译比FFmpeg省事很多对国产化平台比较友好。SRS编译过程大概是git clone -b v4.0 https://github.com/ossrs/srs.git cd srs/trunk ./configure --full make -j$(nproc)编译完生成objs/srs启动就能用。ZLMediaKit是后起之秀最大的特点是协议覆盖面广对国标GB28181、RTSP、RTMP、HLS、WebRTC都有支持。广电场景里经常要接入GB28181的摄像头或编码器ZLMediaKit提供的国标接入能力几乎成了刚需。它的架构更模块化核心库和业务层分离适合做二次开发。缺点是配置项比SRS多上手门槛略高。Nginx-RTMP模块的优势是老团队熟悉毕竟Nginx在广电系统里用得极广。但这个模块本身更新不太活跃而且功能偏基础适合“老项目继续用Nginx做透传”的场景。如果是新项目我不太推荐从它起步因为RTMP之外的能力它覆盖很弱HLS/WebRTC还得另寻出路。三款模块的取舍我用下面这张表说明模块核心优势适用场景安可适配注意SRS直播分发性能强配置简单大规模RTMP/HLS直播分发编译依赖少注意openssl版本ZLMediaKit多协议覆盖国标接入强需要GB28181/多协议融合的业务依赖较多编译参数需仔细配置Nginx-RTMP与Nginx生态天然融合老旧系统平滑升级模块更新慢新协议支持弱3.3 播放与协议适配hls.js、video.js、flv.js服务端准备好了终端播放侧也有对应的开源模块。广电业务里有大量Web播放页面播放器不能只认一种协议。老系统里播放器多是Flash方案现在早就淘汰了必须走HTML5技术栈。前端播放常用的开源模块包括hls.js由视频社区维护的HLS播放器库纯JavaScript实现兼容性好在安可后的Web页面上能直接跑不需要额外插件。video.js老牌播放器框架支持插件机制适合需要高度定制播放界面的场景。配合hls.js或flv.js插件使用。flv.js面向HTTP-FLV协议的播放库低延迟直播场景常用。注意它依赖Media Source Extensions浏览器必须支持这点需要在实际终端环境里做测试。选播放器模块时我建议优先hls.js。原因很简单广电业务的播出质量要求高HLS切片方案容忍网络波动能力强而且hls.js在国产浏览器、基于Chromium的终端上的兼容性已经相当成熟。如果你的业务要求低延迟再考虑HTTP-FLV或WebRTC路线。3.4 周边配套调度、监控与接入模块视频服务器不能只有视频处理本身周边的接入、调度、监控同样缺不了。接入侧如果要从摄像头或GB28181设备拉流可以用ZLMediaKit的国标模块也可以配合开源的SIP协议栈把设备注册、信令交互、媒体流拉取串起来。调度侧开源领域没有专门针对广电视频服务器的调度模块但可以拿通用消息队列和缓存来搭。比如用Redis保存任务元数据用消息队列分发转码任务再用一套简单的HTTP API把任务状态串起来。这个组合不复杂胜在稳定。监控侧Prometheus node_exporter是通用方案主要用于采集服务器CPU、内存、磁盘、网络指标。更细粒度的业务监控比如当前并发流数、转码队列长度、HLS切片生成延迟需要自己在FFmpeg和SRS调用链里埋指标。我建议在SRS上开启官方支持的Prometheus监控接口FFmpeg则靠脚本定期探测转码进程的状态和输出文件的时间戳。4. 实操记录在国产化服务器上从编译到出流4.1 环境准备与工具链我在项目的试验环境是一台某国产CPU架构的服务器搭配某国产Linux发行版内存32GBCPU核数16。一台典型的安可视频服务器配置大抵如此。拿到机器第一步先确认基础信息uname -m cat /etc/os-release gcc --version如果gcc都没有先装编译工具链。不同发行版包管理器不同但大逻辑一致yum install -y git gcc gcc-c make cmake autoconf automake libtool pkgconfig这里有个经验编译FFmpeg之前一定要先确认pkgconfig和make可用。很多编译失败其实不是代码问题而是环境缺了基础工具。4.2 编译依赖库与FFmpeg我习惯的顺序是先编x264再编x265接着fdk-aac最后才是FFmpeg。每个库的configure参数不需要太多按默认参数来就好。比如x264./configure --enable-shared --enable-pic --prefix/usr/local make -j8 make install ldconfig每个库装完后用ls /usr/local/lib确认生成文件同时要确认pkg-config能找到它pkg-config --modversion x264FFmpeg configure时它会自动检测这些库。如果检测不到最常见的两个原因一是库装到了非默认路径需要设置PKG_CONFIG_PATH二是缺少开发头文件编译库时没带--enable-shared导致头文件没安装。FFmpeg编译时间取决于机器性能。16核机器全编一次大概20到40分钟。第一次编译最好执行make -j8不要盲目用-j16如果内存不够32GB过大的并行度会导致内存吃满、进程被杀。编译完验证一下转码能力ffmpeg -i test_1080p.mp4 -c:v libx264 -preset veryfast -c:a aac out.mp4只要这条命令能顺利走完说明FFmpeg核心链路打通了。4.3 配置SRS跑通直播流FFmpeg编好后我接着部署SRS做分发测试。SRS配置非常简洁一个基本的直播分发配置如下listen 1935; max_connections 1000; daemon on; srs_log_tank console; vhost __defaultVhost__ { hls { enabled on; hls_path /data/hls; hls_fragment 2; hls_window 10; } }启动SRS./objs/srs -c conf/rtmp_hls.conf然后用FFmpeg推流ffmpeg -re -i test_1080p.mp4 -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -f flv rtmp://127.0.0.1:1935/live/test这里-re参数很重要它让FFmpeg按视频原速率推流防止瞬间发完数据包导致服务器端缓冲异常。拉流验证用VLC或者ffplay都行ffplay rtmp://127.0.0.1:1935/live/test如果拉流稳定、画面不卡SRS这条链路就算通了。再打开HLS配置后可以直接播放http://服务器IP:8080/live/test.m3u8。4.4 用FFmpeg切片HLS并验证直播之外广电业务大量涉及点播与回看HLS切片是常用能力。我常用下面的命令把素材切成HLS流ffmpeg -i input.mp4 -c:v copy -c:a copy \ -f hls -hls_time 4 -hls_list_size 0 \ -hls_segment_filename /data/hls/seg_%03d.ts \ /data/hls/index.m3u8-hls_time 4表示每4秒一切片-hls_list_size 0表示m3u8索引里保留所有切片。对回看业务需要保留全部切片对直播业务反而要设置-hls_list_size 5之类的小值让播放器只看到最近几个切片。验证方法很简单把m3u8和ts放进Web目录用hls.js在浏览器里播放。我一般会再用脚本检查m3u8里每个ts切片文件是否存在以及切片时长是否均匀防止播出时出现卡顿。5. 常见问题与排障技巧实录5.1 编译期最容易翻车的三个点安可环境下编译开源模块翻车率最高的三个点我总结如下。第一找不到nasm/yasm汇编器。编译x264或FFmpeg时configure阶段报错“require yasm”。原因是x86架构下需要汇编器处理优化代码。解决方法是先安装nasm或者对FFmpeg加编译参数禁用x86汇编优化。但在性能敏感场景我推荐前者因为x264在x86下没有汇编优化性能差距能到两倍以上。ARM架构平台不受这个影响但要注意ARM汇编工具链的版本。第二系统库版本过低。不少国产Linux发行版内置的OpenSSL、zlib版本都比较保守某些较新版本的流媒体模块会要求更高版本。这时候我不建议直接升级系统库因为系统库被很多基础组件依赖升级容易引入连锁问题。稳妥做法是编译一个独立版本放到自定义路径用环境变量或软链接指过去。第三编译过程内存爆掉。国产化服务器内存配置差异很大有的机器只有16GB。FFmpeg开启多路并行编译时内存轻松吃满。我用16核机器编译时会把并行数压到8再配合--disable-doc这类减小编译体积的选项。5.2 运行期的资源与性能问题编译过了运行期依然会有坑。文件句柄数不够。SRS这类流媒体服务在高并发下要大量建立socket连接。默认的ulimit -n可能只有1024几百路并发时服务直接拒连。必须调大ulimit -n 65535同时要在系统配置里改/etc/security/limits.conf否则重启失效。CPU占用过高。转码本身吃CPU是正常的但如果纯转码时CPU占用异常高先检查FFmpeg是否用了硬件加速或SIMD优化。查编译日志看有没有输出NEON enabled相关信息。我遇到过有的编译参数把CPU特性检测禁了导致FFmpeg全程走C语言路径性能惨不忍睹。内存泄漏。长转码任务跑几天几夜时RSS内存持续上涨基本就是有内存泄漏。优先把FFmpeg升级到较新版本很多历史泄漏都是老版本bug。如果用的是SRS开启--gc内存回收机制并且定期检查日志中的告警信息。5.3 业务侧的流异常业务侧最常见的异常是“推流正常、播放黑屏”或者“画面花屏”。排查思路要按协议分层走先确认拉流地址参数正确再确认码流本身没有异常。用ffprobe检查推流上去的码流是不是GOP结构正常有关键帧缺失的话播放器起播就会黑屏。检查音视频时间戳是否同步可以用FFmpeg输出日志观察Non-monotonic DTS这类提示。如果是HLS播放卡顿优先查切片时长是否均匀以及服务器到终端的网络抖动。安可环境下多了一类特殊问题不同终端播放器的协议兼容性不一致。有的终端只支持HLS有的只支持HTTP-FLV。我的做法是在分发层同时开放多协议让播放器自动选路这正好能体现ZLMediaKit这类多协议模块的价值。6. 组合推荐两套方案供参考基于前面的实操我给两类典型场景各配了一套方案。方案A轻量直播分发场景适用情况单路或多路同步直播、点播回放终端规模中等团队对Nginx体系熟悉。处理与切片FFmpeg libx264/libx265分发服务SRS开启HLS HTTP-FLV播放器hls.js / flv.js监控Prometheus node_exporter这套组合依赖少、部署快我实测在两台服务器上跑几十路直播完全没有问题适合快速交付。方案B综合全业务场景适用情况需要接入GB28181设备、输出WebRTC低延迟流、还要承载多协议分发团队有二次开发能力。信令接入ZLMediaKit内置GB28181信令模块处理与切片FFmpeg x264 x265分发服务ZLMediaKitRTSP/RTMP/HLS/WebRTC全协议播放器video.js hls.js WebRTC插件调度与监控Redis 消息队列 Prometheus Grafana方案B的复杂度高一些但胜在统一协议出口。广电业务如果未来要扩展到低延迟互动场景方案B不用推翻重来。7. 最后说几句大实话做安可适配这一年多我最大的体会是开源模块本身都不是什么秘密武器真正的难点在于组合后的工程化能力。FFmpeg谁都会装但能不能针对特定CPU架构调好编译参数能不能让转码和分发两个环节之间的协议严丝合缝这才是区分“能跑”和“能上线”的分水岭。我的建议是拿到任何一套方案先在目标机器上把最小闭环跑通一遍采集或推流进来转码切片播放器拉流全部串起来。不要在还没有最小闭环之前就去优化并发、优化画质。基础链路通了后面的事情都是渐进式的调优。另外所有开源模块拉下来以后第一时间锁定版本不要追求“最新”。安可环境里用的软件栈组合很讲究匹配关系一个模块升级可能连带要求另一个模块升到指定版本然后整个编译链就崩了。我自己吃过这个亏之后都老老实实在README里写清楚版本矩阵。最后分享一个小技巧把整个编译过程写成脚本保存下来。不只是对着终端敲命令而是每一步都做成可复现的脚本。因为安可环境下你经常会遇到“换一台机器就要全部重来”的情况有脚本在手部署时间能从半天压缩到半小时。这也是我觉得整个项目里最值得投入的一笔时间投资。
RELATED READING

延伸阅读

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