尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

wvp-GB28181-pro与ZLMediaKit国标视频平台部署联调实战

wvp-GB28181-pro与ZLMediaKit国标视频平台部署联调实战 1. 先搞清楚这套组合各自干什么wvp-GB28181-pro 与 ZLMediaKit 的分工GB28181 这套东西刚接触的人最容易卡在一个地方不知道信令和媒体流是两条完全独立的链路。我最早做项目的时候把 SIP 信令调通了看到设备在平台上显示在线就以为大功告成结果点播的时候黑屏查了一整天才反应过来——信令通了只代表我知道你在媒体流能不能过来是另外一回事。所以这篇东西我打算从职责边界讲起先把 wvp-GB28181-pro 和 ZLMediaKit 这两块拼图的位置摆正后面的部署步骤才不会变成照抄命令却不理解在干什么。wvp-GB28181-pro 在整个架构里扮演的是信令控制与业务管理的角色。它是一个基于 Spring Boot 的 Java 项目核心职责包括作为 SIP 服务器接收国标设备或下级平台的注册、处理心跳保活、响应目录查询、下发 INVITE 邀请设备推流、处理录像回放的信令交互、管理设备与通道的业务数据、对外提供 Web 页面和 REST 接口。你可以把它理解成一个调度中心它自己不碰视频数据只管发号施令和记账。ZLMediaKit 则是纯粹的流媒体处理引擎。它接收来自设备的 RTP 流、完成解复用和转封装对外输出 RTSP、RTMP、HTTP-FLV、HLS、WebRTC 等多种播放协议同时负责录像存储、按需拉流、流媒体转发。国标设备推流过来的时候实际落到 ZLMediaKit 的 RTP 收流端口上播放器播放的时候实际是从 ZLMediaKit 的 HTTP 或 RTSP 端口取流。wvp 只是在中间告诉 ZLMediaKit有这么一路流要开个端口收以及告诉播放器去这个地址取流。两者之间靠Hook 回调和REST API打通。wvp 在配置文件里声明 ZLMediaKit 的地址和密钥ZLMediaKit 在config.ini里把 hook 地址指向 wvp。当有流注册上来、流无人观看、录像完成、需要鉴权的时候ZLMediaKit 主动回调 wvp当 wvp 需要创建 RTP 接收端口、关闭某路流、查询在线流的时候调用 ZLMediaKit 的 HTTP API。这条双向通道是整套系统能不能跑起来的命脉后面配置里任何一个环节写错表现都是设备在线但点播失败非常隐蔽。1.1 为什么不干脆用一个组件搞定很多人会问网上有些单体方案一个进程既做信令又做流媒体为什么还要拆成两个。我的实际体会是拆分带来的好处在规模上来之后才明显。流媒体处理是 CPU 和带宽密集型的工作一个 ZLMediaKit 实例扛不住了可以直接再起一个wvp 通过多媒体节点配置把负载分散出去而信令和业务逻辑相对轻量稳定运行即可。反过来如果耦合在一起扩流媒体就得连业务一起复制数据库连接、定时任务全都会重复执行运维会很难受。另外 ZLMediaKit 是 C 写的性能和并发连接数上有天然优势单独维护它的编译和调优比把它塞进 Java 进程里要省心。所以这套组合的分工不是设计冗余而是各自做自己最擅长的事。理解这一点之后你在排查问题时就有一把尺子播放相关的画面问题优先查 ZLMediaKit 侧注册、目录、云台控制、录像检索这类问题优先查 wvp 侧。1.2 适用的场景与规模边界这套方案最典型的使用场景是中小规模的视频监控汇聚平台几十到几百路设备接入需要国标级联、需要 Web 端和移动端播放、需要基础的录像和回放。它不像大型商业平台那样有完善的集群和容灾但胜在开源、可控、能改。我见过不少项目拿它做园区的监控整合、做行业设备的统一接入、做产品原型验证都是合适的。不适合的场景也要说清楚如果你需要上千路并发、需要跨机房容灾、需要商业级的 SLA 保障那这套东西的运维成本会快速上升你要自己补的东西很多比如媒体节点的健康检查、流的自动恢复、数据库的高可用。评估的时候心里要有数别指望开箱即用能顶住生产级别的压力。2. CentOS 7 基础环境准备绕不开的换源与依赖坑CentOS 7 现在部署这套系统第一个拦路虎不是技术问题而是系统本身已经停止维护了。官方 YUM 源在 2024 年年中之后逐步下线你如果拿一个原版镜像装完直接yum install大概率会卡在报错上下不来。所以这一步我建议直接把换源做掉用 vault 归档源或者国内镜像站别在源的问题上浪费时间。我踩过一次坑装了一半发现某个依赖死活拉不下来查了半天才发现是源失效不是依赖冲突白白折腾了一个下午。2.1 系统初始化的几个必做项安装系统的时候我一般选最小化安装Minimal Install把不必要的服务砍掉减少后续排查干扰。装完之后先做几件事更新系统补丁在源可用前提下、设置静态 IP、同步时间、关闭或者正确配置防火墙和 SELinux。时间同步这个事看着小但对 SIP 信令影响不小。国标设备注册的时候会带时间戳有些设备对时间偏差敏感服务器时间和设备时间差太多会导致注册失败或者鉴权异常。用chronyd配置 NTP 同步即可内网没有 NTP 服务器的话至少保证服务器本身时间准确。SELinux 我一般设成permissive而不是直接关掉。直接disabled在有些环境里是合规问题而permissive只会记录警告不会真正拦截排查阶段够用了。等系统稳定运行一段时间确认没有 AVC 拒绝日志再考虑收紧策略。防火墙方面如果用 firewalld那就老老实实按端口开放如果是纯内网测试环境图省事直接停掉也行但生产上别这么干。2.2 CentOS 7 的编译工具链问题这是一个必须重点说的坑。CentOS 7 自带的 GCC 是 4.8.5CMake 是 2.8.12而 ZLMediaKit 的编译需要较新的 CMake至少 3.1实践中我建议 3.13 以上和能完整支持 C11/14 的编译器。直接用系统默认工具链去编译十有八九在 CMake 检测阶段就报版本不够或者编译过程中报一堆语法错误。解决办法是用 SCLSoftware Collections装devtoolset。装完之后通过scl enable devtoolset-9 bash切换环境或者干脆在脚本里把新工具链加到 PATH 前面。这一步做完编译基本就顺了。另外 CMake 我倾向于单独下载官方预编译包解压使用比从源码编译省事得多。提醒一句devtoolset只是临时切换环境变量新开一个终端就失效了。如果你按照某个教程编译成功换了窗口再执行同样的命令却失败先想想是不是忘了切环境。2.3 端口规划要提前做端口冲突是部署阶段最常见的低级事故。这套系统涉及的端口比较多我建议先在纸上列一张表把每个端口分配给谁、用什么协议、是否对外暴露都想清楚再动手。下面是我常用的端口规划你可以按自己环境调整。端口协议归属组件用途5060UDP/TCPwvpSIP 信令监听8080 或自定义TCPwvpWeb 页面与 REST 接口80 / 443TCPZLMediaKitHTTP 播放、HLS 分发554TCPZLMediaKitRTSP 播放1935TCPZLMediaKitRTMP 播放与推流30000-30500UDPwvp/ZLMediaKitRTP 收流端口段6379TCPRedis缓存与会话仅本机3306TCPMySQL数据库仅本机RTP 端口段需要特别注意两点一是要留够数量每路实时流会占用一个端口路数多了端口不够用二是端口段要和 wvp 配置、ZLMediaKit 配置、防火墙三处保持一致任何一处对不上都会导致收流失败。这个端口段通常是设备推流的目标端口由 wvp 在 INVITE 的 SDP 里告诉设备所以它必须和 ZLMediaKit 实际监听的端口范围匹配错一位都不行。2.4 数据库和缓存的准备MySQL 我一般用 5.7 或 8.0用 8.0 的话注意 JDBC 驱动和连接串要匹配时区参数也要加上否则可能出现时间存进去差 8 小时的问题。字符集统一用utf8mb4因为设备名称、通道名称里可能有生僻字或者特殊符号。数据库的max_connections适当调高一点wvp 的连接池加上后续可能的多实例默认的 151 有时候会不够。Redis 主要用来存会话、流状态、设备订阅关系这些东西。单机部署的话默认配置基本够用但要设个密码并只监听本机别裸奔在公网上。我见过有人的 Redis 直接暴露在外网没设密码被写进去一堆垃圾键虽然不影响业务但这是个安全隐患顺手配上密码成本几乎为零。3. ZLMediaKit 部署从编译到收流参数调优ZLMediaKit 是整套系统里最挑环境的部分也是决定画质和稳定性的核心。我的建议是能编译就编译不要随便下别人打包的二进制。原因很简单编译过程会检测你的系统依赖编出来的版本和你的库版本是一致的而随手拿来的二进制可能链接了不同版本的 OpenSSL 或 ffmpeg 库运行时报一堆symbol lookup error排查起来很折磨。3.1 编译流程与关键依赖标准流程是克隆源码、初始化子模块、CMake 配置、编译安装。这里有几个细节值得强调。第一一定要用git clone --recursive或者克隆后执行子模块初始化因为 ZLMediaKit 依赖 ZLToolKit 等子模块漏了会编译失败。第二如果机器内存比较小比如 2G并行编译容易 OOM把make -j的并发数降下来-j2甚至单线程慢一点但稳。第三编译前确认 OpenSSL 开发包已安装否则 HTTPS、WebRTC 相关功能会缺失。编译完成之后产物是MediaServer可执行文件默认配置文件是config.ini。建议不要直接在源码目录跑把可执行文件和配置拷到一个独立的运行目录配好 systemd 服务这样升级和备份都清爽。# 编译 ZLMediaKit 的大致流程在已切换 devtoolset 环境的终端中执行 git clone --depth 1 https://github.com/ZLMediaKit/ZLMediaKit.git cd ZLMediaKit git submodule update --init mkdir -p build cd build cmake .. -DCMAKE_BUILD_TYPERelease -DENABLE_WEBRTCON make -j4 sudo make install3.2 config.ini 里和国标最相关的几项config.ini项目很多但真正决定国标能不能跑通的就那么几项。我把它拆开讲每一项都说说为什么这么设。[general]段的enable保持默认mediaServerId建议自定义一个有意义的名字比如media-01。这个 ID 会出现在 wvp 的媒体节点配置里两边必须一致。用默认的随机值也能跑但你以后加第二个媒体节点的时候会分不清谁是谁。[http]段设置 HTTP 监听端口和rootPath。这个端口是播放器取 FLV/HLS 的地方也是 wvp 回调 ZLMediaKit 的部分接口地址所在要保证 wvp 能访问到。[rtsp]和[rtmp]段按需开启端口保持默认 554 和 1935 即可。如果你不需要某一种协议关掉能省点资源。[rtp_proxy]段是重点。port设置 RTP 收流的默认端口但真正收流时用的端口是由 wvp 通过 API 动态创建的落在 wvp 配置的端口段里。这里要理解一个机制wvp 在收到播放请求后会调用 ZLMediaKit 的/index/api/openRtpServer接口指定一个端口让 ZLMediaKit 开始监听然后把这个端口写进 SDP 发给设备。设备往这个端口推流ZLMediaKit 收到后回调 wvp 通知流来了。[hook]段是双向通道的关键。enable1打开 hookon_flow_report、on_publish、on_play、on_stream_changed、on_stream_none_reader、on_server_started这些回调地址统统指向 wvp 的/index/hook接口。admin_secret要设一个强密码wvp 侧配置的 media secret 必须和它一模一样否则 wvp 调用 ZLMediaKit API 时会一直返回鉴权失败。[ffmpeg]段如果你需要 HLS 切片或者录制转 MP4bin路径要指向正确的 ffmpeg 可执行文件。CentOS 7 自带的 ffmpeg 版本老我一般自己装一个新版本写绝对路径。3.3 收流缓冲与性能相关的内核参数国标设备推流是 UDP 的UDP 的特点是丢了就丢了不重传。如果服务器的 socket 接收缓冲区太小或者内核网络参数设置保守在高码率或者网络抖动的情况下就会丢包表现是画面卡顿、花屏、马赛克。这不是 ZLMediaKit 的 bug是系统层面的问题。我一般会调整几个参数把net.core.rmem_max和net.core.rmem_default调大允许 socket 使用更大的接收缓冲把net.core.netdev_max_backlog提高应对瞬间的包洪峰对于大量并发的场景net.ipv4.udp_mem也可以适当放宽。这些改动写到/etc/sysctl.conf里sysctl -p生效。注意这些参数不是越大越好盲目调大只是把内存压力往后推。调完之后要用实际业务压一压观察丢包和延迟根据数据微调别照抄一个数字就完事。另外就是 CPU 亲和性和网卡多队列。如果服务器网卡支持多队列而流量又集中在少数几个队列上可能出现单核跑满而其他核空闲的情况。可以通过ethtool查看队列分布必要时调整 RSS 或给 MediaServer 进程绑核。这一步属于优化范畴流量不大的时候可以先不管等真的遇到瓶颈再处理。4. wvp-GB28181-pro 部署信令配置与国标对接wvp 这块的部署说到底就是编译打包、配数据库、改配置文件、跑起来。真正花时间的不是敲命令而是理解配置文件里那几个 IP 到底该填什么。我见过太多人卡在这里设备注册上了但点播地址是内网 IP播放器在外网取不到流或者 hook 地址填的是127.0.0.1结果 ZLMediaKit 在另一台机器上回调永远发不过来。4.1 数据库初始化与后端启动先把 MySQL 建库建表导入项目提供的 SQL 脚本。然后改application.yml或按版本对应的application-dev.yml里的数据库连接、Redis 连接、服务端口。这些配置项比较直白照着改就行。要留意的是数据库账号的权限别用 root 跑业务单开一个账号只授权这个库的增删改查。后端打包用 Maven构建产物是一个可执行的 jar。启动方式我建议用nohup java -jar或者直接写 systemd 服务。systemd 的好处是能配自动重启、能统一管理日志、开机自启也方便比裸nohup规范得多。# 以 systemd 服务方式启动 wvp 后端 [Unit] DescriptionWVP GB28181 Platform Afternetwork.target mysqld.service redis.service [Service] Typesimple WorkingDirectory/opt/wvp ExecStart/usr/bin/java -jar /opt/wvp/wvp.jar --spring.config.location/opt/wvp/application.yml Restarton-failure RestartSec10 [Install] WantedBymulti-user.target4.2 配置文件里的 IP 到底怎么填这是全篇我认为最值得反复强调的部分。wvp 的配置文件里有好几个 IP 字段名字相似但用途完全不同填错了就是能注册不能播放或者内网能播外网不能播。我按用途把它们分清楚。SIP 相关配置里的ip是 SIP 信令服务器监听的地址一般是本机内网 IP。domain是 SIP 域通常填一个 10 位的行政区划编码符合国标规范。id是平台自身的国标编码同样是 10 位数字。password是平台和下级设备或平台之间鉴权用的密码要保证双方一致。媒体节点配置里的ip是 ZLMediaKit 的地址hook-ip是 ZLMediaKit 主动回调 wvp 时用的地址——这个特别容易填错。如果 wvp 和 ZLMediaKit 在同一台机器hook-ip填127.0.0.1没问题如果分开部署就要填 wvp 所在机器的、ZLMediaKit 能访问到的 IP。sdp-ip是写进 SDP 里告诉设备往哪个 IP 推流的地址必须是设备能访问到的 ZLMediaKit 地址。stream-ip是播放时拼给播放器的地址必须是播放器能访问到的地址。secret要和 ZLMediaKit 的admin_secret一致。这四个 IP 字段在很多部署环境里其实是同一个值导致大家以为它们无所谓一旦网络环境复杂起来比如多网卡、NAT、内外网分离就暴露出区别了。我的建议是先在单网卡环境跑通理解每个字段的作用再去处理复杂网络。配置项作用单机常见填法复杂网络注意事项SIP ipwvp 信令监听地址本机内网 IP多网卡时选设备可达的网卡media ipZLMediaKit 地址127.0.0.1 或本机 IPwvp 能访问到即可hook-ipZLMediaKit 回调地址127.0.0.1需 ZLMediaKit 可达sdp-ip设备推流目标地址本机 IP必须是设备可达地址stream-ip播放地址前缀本机 IP必须是播放器可达地址secretAPI 鉴权密钥自定义强密码与 ZLMediaKit 一致4.3 前端打包与访问前端是 Vue 项目打包后是静态文件通常由后端托管或者交给 Nginx。用后端托管最省事打包好的文件放到指定目录即可访问http://服务器IP:端口就能打开。用 Nginx 托管的好处是可以配 HTTPS、可以做静态资源的缓存优化生产环境我倾向于用 Nginx。打包的时候注意后端的接口地址配置别把localhost打进生产包里否则前端在浏览器里请求localhost肯定失败。这个坑很经典本地开发不觉得有问题一上线就白屏或者接口全 404。4.4 设备接入与级联配置设备接入有几种情况设备主动注册到 wvp或者 wvp 主动去注册到设备。前者是最常见的设备里配置平台的 SIP 服务器 IP、端口、域、平台 ID 和密码设备上线后就会周期性地发注册和心跳。wvp 侧只要保证这些参数和配置一致设备就会显示在线。级联是另一回事指的是平台和平台之间对接。wvp 可以配置为上级平台接收下级平台的注册也可以配置为下级平台主动注册到上级。配置级联的时候要特别留意两个方向注册方向决定了谁主动发注册请求媒体方向决定了点播请求从哪边发起。这里回答一个搜得比较多的问题上级平台想主动向下级联拉取资源为什么有时候不行。核心在于级联方向的定义和注册机制。如果下级平台配置的是主动注册到上级那么下级会定期向上级发送注册和目录推送上级侧能看到设备目录如果下级配置成被动接收上级注册那上级需要主动去连下级此时上级才能掌握主动性。实际使用中出现的上级拉不到下级资源很多时候是下级没有把目录推上去或者上级的 SIP 域、编码和下级对不上导致目录查询响应被丢弃。排查这类问题先从抓包看双方 SIP 消息的交互情况入手比在页面上瞎点有效率得多。5. 全流程联调与故障排查实战部署完不等于能用联调才是真正见功力的地方。我把它分成能不能注册能不能看到目录能不能点播能不能回放四个递进的关卡一关一关过出问题的时候也能快速定位到是在哪个环节断的。5.1 用抓包定位信令问题信令问题的排查抓包几乎是最有效的手段。因为 SIP 交互有固定的消息序列注册是 REGISTER 加 401 挑战加带鉴权的 REGISTER心跳是 MESSAGE目录查询是 MESSAGE 带 XML body点播是 INVITE 加 ACK。你抓一段包看到消息停在哪一步基本就知道问题在哪。比如只看到 REGISTER 没看到 401说明请求根本没到 wvp可能是端口不对或者防火墙拦了看到 401 但设备不再发第二次 REGISTER说明设备的鉴权算法或者密码有问题。抓包建议在服务器上抓用tcpdump指定 5060 端口抓下来的包拖到 Wireshark 里用sip过滤器一筛交互序列一目了然。如果设备侧也能抓两边对照着看更清楚能判断是包没出去还是没回来。5.2 常见问题速查我把这几年遇到的高频问题整理成一张表排查的时候可以按表现对号入座。表里的每一项都是在实际环境里验证过的不是凭空列出来的。现象常见原因排查方向设备一直离线注册失败或心跳超时抓包看 REGISTER 与 401核对域和密码设备在线但无目录目录查询未响应或 XML 解析失败看 MESSAGE 的 XML检查编码格式点播黑屏无画面收流端口不通或 sdp-ip 填错确认 ZLMediaKit 是否收到 RTP检查 firewall画面卡顿花屏UDP 丢包或缓冲不足调内核缓冲检查网络质量与码率播放地址外网打不开stream-ip 填了内网地址改为公网可达地址或用转发wvp 调用媒体接口失败secret 不一致核对两侧密钥看 ZLMediaKit 日志回放检索不到设备不支持或时间范围错误确认设备能力检查查询时间段级联目录为空注册方向或域配置不匹配抓包看双方 MESSAGE 与目录推送5.3 语音对讲和录像回放的验证语音对讲是国标里比较容易出问题的功能因为它涉及双向的音频流。平台要下发一个带音频的 INVITE设备要能接收来自平台的 RTP 音频并且播放。配置上一次典型的坑是设备的音频编码和平台不一致比如设备只支持 G.711A 而平台协商成了别的格式结果就是听不到声音。验证的时候先在 wvp 页面上操作对讲同时抓 RTP 包看有没有音频数据从平台发向设备再确认设备的扬声器设备是否被占用。录像回放走的是另一套信令平台下发带回放标识的 INVITESDP 里指定回放时间和倍速设备用 RTSP 或 RTP 回传历史视频。回放不成功的时候先确认设备本身支不支持录像回放有些设备只支持实时不支回放再看时间段的格式对不对国标里时间是带时区的格式写错设备会直接拒绝。6. 长期运行要做的几件事系统跑起来只是开始能不能稳定运行半年一年取决于你在运维上做了多少准备。这一块我不讲大道理只讲我自己在实际项目里会做的具体动作。6.1 日志与监控日志分散在三个地方wvp 的 Java 日志、ZLMediaKit 的运行日志、MySQL 和 Redis 的日志。我一般用 systemd 把前两者的标准输出收集起来配合 logrotate 做轮转避免日志把磁盘写满——这个事我真实遇到过ZLMediaKit 日志没有轮转跑了一个月磁盘告警排查半天发现是日志占了几十 G。监控方面至少要盯几个指标媒体节点的 CPU 和内存、网络带宽、当前在线流数量、设备在线率。ZLMediaKit 提供了获取服务器统计信息的 API可以定时拉取写到监控系统里。设备在线率这个指标特别有用它能在用户投诉之前告诉你哪台设备掉线了。6.2 容量规划和扩展一个 ZLMediaKit 实例能扛多少路取决于分辨率和码率。1080P 4Mbps 的流和 720P 1Mbps 的流承载能力差好几倍。评估的时候别只看路数要看总带宽和转封装的开销。如果开了 HLS 切片CPU 消耗会明显上升因为要持续转封装和切片。扩展的思路是按需增加媒体节点。wvp 支持配置多个媒体节点新设备接入的时候可以指定用哪个节点。这里的关键是流媒体节点之间能不能互相转发——如果多节点之间需要转发流那节点之间的网络带宽就是瓶颈规划的时候要算进去。6.3 备份和升级数据库要定期备份wvp 的设备配置、通道信息、用户权限都在里面丢了重建很麻烦。备份用mysqldump定时跑就行存到异地或者对象存储里。配置文件wvp 的 yml、ZLMediaKit 的 config.ini也要纳入版本管理改之前先备份别直接在服务器上手改不留底。升级的时候先在测试环境验证尤其 ZLMediaKit 和 wvp 之间有版本匹配关系某些 API 或 hook 参数在不同版本之间有变化跨版本升级可能导致功能异常。升级前把关键的配置项列一个清单升级后逐项比对避免新版配置项默认值变了把原有功能搞坏。这套系统说白了就是信令加媒体两件事理解了这层剩下的都是配置和排查的活儿。我个人最大的体会是别急于一次把功能全开先把注册和实时点播跑通再加回放、加级联、加对讲一步一步来每加一个功能就验证一遍。这样出问题的时候范围永远是新加的那部分排查成本非常低。反过来一上来全配齐结果几十个配置项同时可能是错的那才是真正的噩梦。
返回列表