香港服务器结合大带宽与多线 BGP 分流,如何优化跨境直播带货高峰期的推流与回放?

618促销的前夜02:00。香港机房 18°C 的空调在头顶呼呼作响,机柜风扇像成排的小涡轮咆哮,交换机指示灯在黑暗里一明一灭。监控大屏上,OBS 的推流码率像心电图一样起伏,时不时刺出一根尖峰。去年的这个时刻,我们被跨境链路的抖动按在地上摩擦:丢包一度飙到 3%+,P95 RTT 破百,弹幕版面只剩一句话——“卡到爆”。那口气我咽不下去,直接在香港拉了一批 10G 大带宽机器,叠上多线 BGP,把推流与回放从逻辑到网络彻底拆开:SRT 顶上首跳,策略路由把大陆与海外分道而行,前端再用 CDN 扛住洪峰。一路踩坑、边修边跑,链路终于稳住了。这篇文章就是那次从零到一的完整复盘:思路、参数、配置、演练与回滚,全部摊开——你可以照着搭,今晚就能上。
场景与目标
业务场景:大陆主播在内地通过 OBS 推 RTMP/SRT 到香港,香港作为跨境首跳完成接入、转码、打包(HLS/LL-HLS/WebRTC)、再经内地 CDN 回源进行全国分发。
技术目标:
- 推流稳定:跨境丢包 ≤ 0.5%,RTT 波动可控(P95 ≤ 80 ms)。
- 回放低时延:移动端 HLS P95 起播 ≤ 1.2 s,卡顿率 ≤ 1.0%。
- 弹性抗峰:单集群可承 20 万 QPS 的 .m3u8/.ts 请求,峰值 8–10 Gbps 可稳态输出。
- 可观测与可回滚:出问题能 5 分钟内定位并灰度回滚。
1. 架构总览(接入分层 + 网络分流)
文字拓扑图(简化):
主播(OBS/SRT) --> [跨境] --> HK Ingest层(SRS集群)
|
+--> 转码/打包(FFmpeg/SRS HLS)
|
+--> 回放出口(Nginx/OpenResty + TLS + HTTP/2)
|
+--> 内地CDN(阿里/腾讯/百度等) <-- 终端用户
网络侧:香港机房接两条物理上行(线路 A=CN 优化/CTG/CN2,线路 B=国际混线/本地运营商),机房侧做 多线 BGP 智能入站;我在宿主 OS 上做 策略路由(PBR) 把“去往中国大陆段”的回源/回推走线路 A,海外/CDN/回源健康检查走线路 B,失效自动切换。
2. 选型与规格(我实际落地用的)
2.1 机型与网络
| 角色 | 机型 | CPU | 内存 | 磁盘 | 网卡 | OS |
|---|---|---|---|---|---|---|
| Ingest x3 | 1U 双路 | Intel Xeon Gold 6248R(24C*2) | 128 GB | NVMe 1.92TB *2 RAID1 | 2×10GbE(独立上联) | CentOS 7 |
| Transcode/Pack x2 | 2U | AMD EPYC 7502P(32C) | 256 GB | NVMe 3.84TB *2 RAID1 | 2×25GbE(bond) | CentOS 7 |
| Edge/Origin x3 | 1U | Intel Xeon 4216 | 128 GB | NVMe 1.92TB *2 | 2×10GbE | CentOS 7 |
交换机:ToR 万兆,支持 LACP;上行两条物理链路分别接 线路 A(CN 优化/CN2/CMI/CU专线) 与 线路 B(本地+国际)。
BGP:由机房/服务商提供多线 BGP(入站智能路由)。我不自带 ASN,出站我用策略路由做 PBR。
2.2 软件栈
- SRS 5.x(RTMP/SRT/WebRTC 接入 + HLS/DVR/低延迟优化)
- FFmpeg 6.x(转码切片)
- OpenResty (Nginx 1.21+)(TLS、HTTP/2、缓存、鉴权)
- Prometheus + Grafana(观测)
- Keepalived + 健康检查脚本(线路失效检测与路由切换)
- iptables/ipset + policy routing(目的地分流)
3. OS 基线与内核优化(CentOS 7)
CentOS 7 默认 3.10 内核,开启 BBR 要上新内核。我们用 ELRepo 的 mainline。
# 1) 基础工具
yum install -y epel-release yum-utils wget vim git htop jq net-tools chrony
# 2) 升级内核到 5.x(BBR 支持)
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install -y kernel-ml
# 3) 设置默认引导为新内核
awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg
grub2-set-default 0
reboot
重启后确认:
uname -r
# 5.x 内核
# 4) 开启 BBR + 基础 sysctl
cat >/etc/sysctl.d/99-tune.conf <<'EOF'
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.rmem_default = 67108864
net.core.wmem_default = 67108864
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_notsent_lowat = 16384
net.ipv4.tcp_mtu_probing = 1
net.ipv4.ip_local_port_range = 10000 65535
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
fs.file-max = 1048576
net.netfilter.nf_conntrack_max = 1048576
EOF
sysctl --system
# 5) ulimit
echo '* soft nofile 1048576' >> /etc/security/limits.conf
echo '* hard nofile 1048576' >> /etc/security/limits.conf
# 6) IRQ/NUMA 优化(示例)
yum install -y tuned
tuned-adm profile latency-performance
网卡队列优化(随机型):
ethtool -G eth0 rx 4096 tx 4096
ethtool -K eth0 gro on gso on tso on lro off
4. 多线分流:策略路由(PBR)+ 健康检查
4.1 基础思路
eth0 → 线路 A(CN 优化),eth1 → 线路 B(国际混线)
去往中国大陆网段(China IP 列表)标记为 fwmark=0x1 走 表 100(eth0)
其余目的地 走 表 200(eth1)
Keepalived 定时检测各自默认网关/对端探测 IP,失败则切主或降级到单线。
4.2 配置步骤
1)路由表定义
echo "100 cnline" >> /etc/iproute2/rt_tables
echo "200 intl" >> /etc/iproute2/rt_tables
ip route add default via <GW_A> dev eth0 table cnline
ip route add default via <GW_B> dev eth1 table intl
# 基本优先规则
ip rule add fwmark 0x1 table cnline
ip rule add priority 100 from <eth0_ip>/32 table cnline
ip rule add priority 200 from <eth1_ip>/32 table intl
2)中国大陆 IP 集合(ipset)
实际生产我用离线打包的 China IP 列表(每日生成),示例脚本:
ipset create cn hash:net maxelem 131072
# 伪代码:把china_ip_list.txt逐行塞进ipset
while read -r cidr; do ipset add cn "$cidr"; done < /opt/china_ip_list.txt
3)mangle 标记 + PBR
# 标记去往中国大陆网段的流量
iptables -t mangle -A PREROUTING -m set --match-set cn dst -j MARK --set-mark 0x1
# 保持连接跟踪标记
iptables -t mangle -A PREROUTING -m mark --mark 0x1 -j CONNMARK --save-mark
iptables -t mangle -A OUTPUT -m connmark --mark 0x1 -j MARK
4)Keepalived 健康检查(失效切换)
yum install -y keepalived
cat >/etc/keepalived/keepalived.conf <<'EOF'
vrrp_script chk_line_a {
script "/usr/local/bin/check_gw.sh eth0 219.141.136.10" # 电信DNS为例
interval 3
fall 3
rise 2
}
vrrp_script chk_line_b {
script "/usr/local/bin/check_gw.sh eth1 223.5.5.5" # 阿里DNS为例
interval 3
fall 3
rise 2
}
vrrp_instance ROUTE_HEALTH {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
track_script {
chk_line_a
chk_line_b
}
notify "/usr/local/bin/route_switch.sh"
}
EOF
check_gw.sh(简化):
#!/bin/bash
IF=$1; DST=$2
ping -I $IF -c2 -W1 $DST >/dev/null 2>&1
exit $?
route_switch.sh(根据脚本返回调整 ip route/ip rule,略)
注:rp_filter 必须调为 2(宽松),否则多宿多出口会被内核丢包。
5. 流媒体层:SRS + FFmpeg + Nginx(OpenResty)
5.1 安装 SRS(5.x)
# 依赖
yum install -y gcc gcc-c++ make openssl-devel zlib-devel
git clone https://github.com/ossrs/srs.git /opt/srs
cd /opt/srs/trunk
./configure && make -j$(nproc) && make install
5.2 SRS 核心配置(RTMP/SRT 接入 + HLS)
/usr/local/srs/conf/srs.conf(精简示例):
listen 1935;
max_connections 20000;
srs_log_tank file;
srs_log_file /var/log/srs.log;
daemon on;
# 打开系统站点
vhost __defaultVhost__ {
# 1) 推流接入
ingest livestream {
enabled on;
}
# 2) SRT 接入(跨境抗抖更稳)
srt_server {
enabled on;
listen 10080;
# SRT 建议参数
latency 120
peerlatency 60
maxbw 20000000
passphrase your_srt_psk
pbkeylen 16
}
# 3) HLS 打包
hls {
enabled on;
hls_fragment 2;
hls_window 8;
hls_path /data/hls;
hls_dispose 0;
hls_td_ratio 1.5;
}
# 4) GOP 缓存 + 低延迟
gop_cache on;
queue_length 30;
# 5) 转码(调用 FFmpeg 生成多码率)
transcode live2hls {
enabled on;
ffmpeg /usr/bin/ffmpeg;
engine abr720 {
vcodec libx264; vprofile main; vpreset veryfast; vbitrate 3000;
acodec aac; abitrate 128; asample_rate 44100; achannels 2;
output rtmp://127.0.0.1/live/${app}?vhost=${vhost}/${name}_720p;
}
engine abr480 {
vcodec libx264; vprofile main; vpreset veryfast; vbitrate 1800;
acodec aac; abitrate 96; asample_rate 44100; achannels 2;
output rtmp://127.0.0.1/live/${app}?vhost=${vhost}/${name}_480p;
}
}
}
要点:OBS 在主播端优先 SRT 推入(RTMP 备份)。SRT 的 ARQ/FEC 能显著降低跨境抖动带来的可见卡顿。
5.3 FFmpeg 手工转码示例(可替代/搭配 SRS 内置)
ffmpeg -re -i "rtmp://127.0.0.1/live/room001" \
-c:v libx264 -preset veryfast -b:v 3000k -maxrate 3300k -bufsize 3000k -g 48 -keyint_min 48 -sc_threshold 0 \
-c:a aac -b:a 128k -ar 44100 \
-f hls -hls_time 2 -hls_list_size 4 -hls_flags delete_segments+program_date_time \
-master_pl_name master.m3u8 \
-hls_segment_filename "/data/hls/room001_720p_%04d.ts" \
"/data/hls/room001_720p.m3u8"
5.4 Nginx/OpenResty 作为回放出口(TLS/HTTP2/鉴权)
安装(略),核心配置片段:
worker_processes auto;
worker_rlimit_nofile 1048576;
events { worker_connections 65535; }
http {
sendfile on; tcp_nopush on; tcp_nodelay on;
keepalive_timeout 65;
aio on; directio 4m; output_buffers 16 512k;
# HLS 缓存与范围请求
proxy_buffering on;
proxy_buffers 256 16k;
proxy_busy_buffers_size 64m;
proxy_read_timeout 10s;
# 域名与证书
server {
listen 443 ssl http2;
server_name live.example.hk;
ssl_certificate /etc/pki/tls/certs/live.crt;
ssl_certificate_key /etc/pki/tls/private/live.key;
# 简单 token 鉴权(示例,生产建议HMAC带时效)
if ($arg_token = "") { return 403; }
location /hls/ {
types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; }
add_header Cache-Control "max-age=2, public";
add_header Access-Control-Allow-Origin *;
root /data;
}
}
}
6. CDN 回源与边缘策略(内地用户加速)
我线上用的是“国内大型 CDN”,都支持 回源站点在香港 的场景。
域名:play.example.com CNAME 到 CDN
回源:https://live.example.hk/hls/(香港 Origin)
缓存规则:
.m3u8:缓存 2–5 秒(必须允许 Range/不缓存 301/302)
.ts:缓存 20–60 秒(视延迟与峰值权衡)
回源跟随跳转:开启
协议:边缘开启 HTTP/2,移动端优先 H2;部分 CDN 已支持 QUIC 可灰度开启
独立中国区:边缘节点仅在中国大陆,海外用户另设一个国际域名,走 线路 B 直出
源站限流:Nginx limit_conn/limit_req 防止回源风暴
7. 观测与告警
系统:node_exporter(CPU/Load/IRQ/软中断)、ethtool 统计
SRS:HTTP API 导出 ingest/clients/丢包/码率
Nginx:vhost 维度 2xx/4xx/5xx、TBT、上游时延
链路:到北京/上海/广州/成都/武汉/沈阳等 拨测点 RTT、丢包(mtr 自动汇总)
阈值告警(示例):
- RTMP 推流 P95 丢包 > 0.8%(5 分钟)→ 严重
- HLS 起播 P95 > 1.5s(10 分钟)→ 警告
- 回源 5xx > 0.2%(1 分钟)→ 严重
- 线路 A 健康检查失败 3 次 → 切到线路 B 并 @OnCall
8. 压测与标定
8.1 推流侧(主播模拟)
# SRT 模拟推流
srt-live-transmit file://sample.mp4 srt://live.example.hk:10080?streamid=publish/live/room001&latency=120
# RTMP 备份
ffmpeg -re -i sample.mp4 -c copy -f flv rtmp://live.example.hk/live/room001?token=abc123
8.2 回放侧(HLS 并发)
# m3u8 起播延迟/并发
ab -n 20000 -c 1000 https://play.example.com/hls/room001_720p.m3u8
# ts 文件压力
ab -n 200000 -c 4000 https://play.example.com/hls/room001_720p_0001.ts
9. 真实数据:优化前后对比(我线上观测的一组)
| 指标 | 优化前(去年) | 优化后(今年) |
|---|---|---|
| 跨境推流丢包(P95) | 2.8% | 0.4% |
| 推流 RTT(P95) | 120 ms | 75 ms |
| 起播时间(HLS,P95) | 2.3 s | 1.1 s |
| 卡顿率(会话) | 3.5% | 0.8% |
| 峰值回源带宽 | 6.1 Gbps | 9.4 Gbps |
| 回源 5xx(峰值 10 分钟) | 0.6% | 0.08% |
其中 SRT 接入 + BBR + PBR(中国网段走线路 A) 是质变项;HLS 窗口下调到 2s*4 + CDN 边缘缓存细化,是量变项叠加。
10. 关键参数与建议(速查表)
| 类别 | 参数 | 建议值/说明 |
|---|---|---|
| SRT | latency |
80–160 ms(跨境留冗余) |
| SRT | maxbw |
主播上行*1.5,限制突发 |
| HLS | hls_fragment |
2 s |
| HLS | hls_window |
6–8 s |
| x264 | gop |
2s GOP(25/30/48 帧按帧率设) |
| Kernel | tcp_congestion_control |
bbr |
| sysctl | netdev_max_backlog |
250000 |
| Nginx | worker_connections |
65535+ |
| CDN | .m3u8 缓存 |
2–5s,注意 no-cache 灰度 |
| 路由 | rp_filter |
2(宽松) |
11. 常见坑与现场处理
路由非对称 → RST/丢包
症状:RTMP/SRT 间歇性断流。
处理:rp_filter=2;确保回包沿着同一出口回去(本机源地址绑定 ip rule from)。如果上游 NAT,和机房沟通固定回程。
OBS 推流卡在 1–2 Mbps
症状:主播端上行被拥塞。
处理:SRT 替代 RTMP;主播侧也启用 BBR;避开晚高峰的 Wi-Fi,强制有线。
HLS 404/丢段
症状:客户端时钟不同步。
处理:所有节点启用 chrony 同步;hls_window 稍加大;CDN 允许负一段回源。
回源风暴
症状:边缘大量回源 .m3u8,源被压垮。
处理:Nginx 开 proxy_cache(如启用 OpenResty 可细化 TTL),.m3u8 2s,.ts 20–60s;限速/限并发。
NIC 软中断飙升
处理:ethtool -G 增队列、RPS/XPS,tuned-adm latency-performance,必要时绑核(/proc/irq/*/smp_affinity)。
TLS 握手开销
处理:开启 HTTP/2,合理 Keep-Alive,证书与 ECDSA 优先级;如 CDN 支持 QUIC 可灰度。
12. 上线步骤清单(我真正在机房走的顺序)
- 裸金属装机 → RAID1 → CentOS 7 → 基础工具
- ELRepo 升内核 → BBR → sysctl/ulimit → tuned
- 配置网卡、静态路由、rp_filter
- 部署 ipset+iptables mangle → ip rule/ip route
- Keepalived 健康检查脚本 → 测试线路 A/B 断链切换
- 编译/安装 SRS → 配 srs.conf → 本地回环推流联通
- 部署 FFmpeg → 多码率转码 → 产出 HLS
- 安装 OpenResty → TLS/HTTP2 → HLS 目录映射 → 鉴权
- CDN 配置回源与缓存规则 → 观察边缘命中率
- Prometheus/Grafana → 仪表盘与告警
- 播放器端灰度(5%→20%→50%→100%)
- 压测校验 → 峰值演练(伴随回滚预案)
13. 安全与合规要点
推流鉴权:URL 带时效 HMAC(exp+token),Nginx/OpenResty 校验 Lua 或 secure_link。
DDoS:选择自带清洗/高防的香港 BGP 资源;必要时在 CDN 层做黑洞/JS 挑战。
版权/资质:回放在内地落地分发涉及备案与内容合规,务必与法务确认 ICP/CDN/视听许可 相关事项。
14. 附:几段我在线上跑的配置片段(可直接抄)
14.1 systemd 服务(SRS)
# /etc/systemd/system/srs.service
[Unit]
Description=SRS Media Server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/srs/objs/srs -c /usr/local/srs/conf/srs.conf
Restart=always
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
14.2 简易 HMAC 鉴权(OpenResty Lua 片段)
lua_shared_dict secrets 1m;
init_by_lua_block {
secret = "your_hmac_secret"
}
set_by_lua_block $ok {
local args = ngx.req.get_uri_args()
local token = args.token or ""
local exp = tonumber(args.exp or "0")
if exp < ngx.time() then return "0" end
local uri = ngx.var.uri
local hmac = ngx.encode_base64(ngx.hmac_sha1(secret, uri..exp))
if token == hmac then return "1" else return "0" end
}
if ($ok = "0") { return 403; }
14.3 China IP 列表每日更新(crontab)
# /etc/cron.d/update_cn_ip
5 4 * * * root /usr/local/bin/update_cn_ip.sh && systemctl reload nginx
update_cn_ip.sh 自行实现:下载/对比/原子替换 ipset。
618 当夜的第三场直播刚开场,我盯着 Grafana 的 SRT 丢包曲线从 0.7% 慢慢落到 0.3%,北京/武汉/成都拨测 RTT 稳在 60–80ms。CDN 命中率稳定在 97% 以上,客服频道竟然罕见地清净。运营同事发来一条消息:“这次不卡了,库存顶不住了。”
我笑了下,喝了口已经凉透的美式,把切换剧本从“灰度回滚”翻到“自动扩容”,又把大屏的背景颜色改成了绿色。
下一场马上开始,但我知道,这条跨境链路,已经站住了。
如果你的场景跟我类似——大陆推、香港首跳、内地分发,上面这一整套“大带宽 + 多线 BGP + PBR 分流 + SRT/BBR + HLS/CDN”的组合拳,基本就能稳住直播带货的高峰。