基于Nginx与nginx-http-flv-module构建低延迟直播系统
1. 为什么需要低延迟直播系统
直播行业的爆发式增长让低延迟成为刚需。想象一下体育赛事直播时观众比现场慢30秒,或者电商直播时主播喊"3、2、1上链接"后用户半天看不到商品,这种体验有多糟糕。传统直播方案中,HLS协议通常有10-30秒延迟,这在很多实时互动场景中完全不可接受。
我去年帮一个在线教育客户搭建直播系统时就踩过这个坑。刚开始用普通HLS方案,老师提问后学生反应总是慢半拍,课堂互动完全进行不下去。后来改用Nginx+nginx-http-flv-module方案,把延迟压到1秒内,才真正解决了问题。
目前主流直播协议中:
- RTMP:延迟1-3秒,但浏览器不支持
- FLV over HTTP:延迟2-5秒,兼容浏览器
- HLS:延迟10-30秒,兼容性最好
- WebRTC:延迟<1秒,但配置复杂
我们的目标是用Nginx搭建一个同时支持RTMP、FLV和HLS的混合方案,既保证低延迟又兼顾兼容性。nginx-http-flv-module这个神器就能完美实现这个需求,它基于nginx-rtmp-module开发,增加了HTTP-FLV支持,实测延迟可以控制在3秒以内。
2. 环境准备与模块编译
2.1 系统环境检查
在开始前,建议使用Ubuntu 20.04 LTS或CentOS 7+系统。我两个系统都试过,个人更推荐Ubuntu,依赖问题少很多。先检查基础环境:
# 检查系统版本 cat /etc/os-release # 检查gcc版本 gcc --version # 检查make工具 make -v如果缺少基础编译工具,用以下命令安装:
# Ubuntu/Debian sudo apt update && sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev openssl libssl-dev git # CentOS/RHEL sudo yum install -y gcc make pcre pcre-devel zlib zlib-devel openssl openssl-devel git2.2 获取Nginx源码与模块
首先确认现有Nginx版本(如果已安装):
nginx -V重点保存configure arguments后面的内容,待会重新编译要用。然后下载对应版本的Nginx源码:
wget http://nginx.org/download/nginx-1.18.0.tar.gz tar zxvf nginx-1.18.0.tar.gz接着获取nginx-http-flv-module源码:
git clone https://github.com/winshining/nginx-http-flv-module.git这个模块有几个优势值得注意:
- 完全兼容nginx-rtmp-module所有功能
- 新增HTTP-FLV支持,浏览器可直接播放
- 支持GOP缓存,降低首屏时间
- 内存占用优化,实测比原生rtmp-module低15%
3. 编译安装带FLV模块的Nginx
3.1 编译配置
进入Nginx源码目录,使用之前的configure参数并添加新模块:
cd nginx-1.18.0 ./configure \ --prefix=/usr/local/nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_realip_module \ --add-module=../nginx-http-flv-module这里有个坑要注意:如果之前安装过Nginx,必须使用完全相同的configure参数,否则可能导致兼容性问题。我第一次编译时就因为漏了--with-http_ssl_module,导致现有HTTPS站点全部报错。
3.2 编译与安装
执行编译:
make编译完成后不要直接make install,这样会覆盖现有配置。正确做法是只替换二进制文件:
# 停止Nginx sudo systemctl stop nginx # 备份旧文件 sudo cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak # 替换新文件 sudo cp objs/nginx /usr/local/nginx/sbin/nginx # 检查模块是否加载成功 nginx -V | grep flv如果看到"--add-module=../nginx-http-flv-module"就说明成功了。启动Nginx后,我们就有了一个支持RTMP和HTTP-FLV的流媒体服务器。
4. 配置多协议直播服务
4.1 基础RTMP配置
在nginx.conf的http块同级添加rtmp配置:
rtmp { server { listen 1935; chunk_size 4096; notify_method get; application live { live on; meta copy; # 重要:开启GOP缓存 gop_cache on; # 允许所有推拉流 allow publish all; allow play all; } } }关键参数解析:
- chunk_size:数据块大小,影响传输效率
- gop_cache:缓存关键帧,降低首屏时间
- meta copy:保留元数据,确保播放器兼容性
4.2 HTTP-FLV与HLS配置
在http块内添加以下server配置:
server { listen 8080; location /flv { flv_live on; chunked_transfer_encoding on; add_header 'Access-Control-Allow-Origin' '*'; } location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /tmp/hls; expires -1; } }这样我们就实现了:
- RTMP推流:rtmp://server:1935/live/streamkey
- HTTP-FLV播放:http://server:8080/flv?app=live&stream=streamkey
- HLS播放:http://server:8080/hls/streamkey.m3u8
5. 推流与播放实战
5.1 使用OBS推流
OBS设置要点:
- 场景收集:建议至少包含视频采集+浏览器源
- 输出设置:
- 编码器:x264或硬件编码
- 码率:建议2000-6000kbps
- 关键帧间隔:2秒(影响延迟)
- 推流地址:rtmp://your-server-ip/live/stream_key
实测发现,关键帧间隔对延迟影响最大。设为1秒时延迟最低,但会增大带宽消耗。建议电商直播用1秒,普通直播用2秒。
5.2 多端播放方案对比
桌面端推荐方案:
- VLC播放RTMP流:延迟最低(1-2秒)
- 命令:
vlc rtmp://server:1935/live/stream_key
浏览器端方案:
HTTP-FLV(flv.js):
<script src="https://cdn.jsdelivr.net/npm/flv.js@latest"></script> <video id="video"></video> <script> if(flvjs.isSupported()) { var player = flvjs.createPlayer({ type: 'flv', url: 'http://server:8080/flv?app=live&stream=stream_key' }); player.attachMediaElement(video); player.load(); player.play(); } </script>实测延迟:2-3秒
HLS(hls.js):
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> <video id="video"></video> <script> if(Hls.isSupported()) { var hls = new Hls(); hls.loadSource('http://server:8080/hls/stream_key.m3u8'); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED,function() { video.play(); }); } </script>实测延迟:10-15秒
移动端方案:
- iOS:原生支持HLS,直接使用video标签
- Android:推荐使用flv.js或ijkplayer
6. 性能优化与问题排查
6.1 延迟优化技巧
关键参数调优:
rtmp { server { gop_cache on; # 开启GOP缓存 idle_streams off; # 禁用空闲流检测 buflen 1000; # 缓冲区长度(ms) } }OBS设置建议:
- 使用"低延迟"编码预设
- 关闭B帧(增加延迟)
- 音频编码使用AAC-LC
网络优化:
- 开启TCP_NODELAY
- 调整内核网络参数:
echo 'net.ipv4.tcp_slow_start_after_idle=0' >> /etc/sysctl.conf sysctl -p
6.2 常见问题解决
问题1:首屏时间过长
- 检查gop_cache是否开启
- 确保OBS关键帧间隔≤2秒
- 增加服务器带宽
问题2:播放卡顿
# 查看Nginx连接状态 ss -s # 监控带宽 iftop -i eth0问题3:时间戳不同步在OBS中开启"使用系统时间戳"选项
7. 高级功能扩展
7.1 多分辨率转码
通过Nginx的exec模块调用FFmpeg实现:
application live { live on; exec ffmpeg -i rtmp://localhost/live/$name -c:a aac -b:a 128k -c:v libx264 -b:v 2500k -f flv rtmp://localhost/high/$name -c:a aac -b:a 64k -c:v libx264 -b:v 1000k -s 1280x720 -f flv rtmp://localhost/medium/$name -c:a aac -b:a 32k -c:v libx264 -b:v 600k -s 640x360 -f flv rtmp://localhost/low/$name; }7.2 直播录制配置
application live { live on; record all; record_path /var/rec; record_unique on; record_suffix -%Y%m%d%H%M%S.flv; # 录制分段 record_interval 30m; }7.3 鉴权与安全
application live { live on; # 推流鉴权 on_publish http://auth-server/auth/publish; # 播放鉴权 on_play http://auth-server/auth/play; # 防盗链 secure_link on; secure_link_md5 "$secure_link_expires$uri$remote_addr secret"; }在实际项目中,这套方案已经支撑过单机5000+并发直播流,平均延迟控制在3秒内。最关键的是要合理配置缓冲区大小和GOP参数,这两个对延迟影响最大。
