如何在香港服务器运行 CentOS 7,设置并结合 Nginx + FFmpeg 实现视频转码与分发的一体化架构

我第一次把这套系统落在香港机房,是在8月一个闷热又潮湿的周五晚上。客户催着第二天要做一场 5,000 人同时在线的直播,还要保证点播库里那几百支旧片也能无缝切到 ABR(自适应码率)HLS。我们把机柜开门,风从冷通道灌进来,NVMe 指示灯一串“呼吸灯”闪着。我一边用耳机远程跟剪辑同事确认片源帧率,一边在跳线架上把第二条 10GbE 上行接到运营商 BGP 设备上。凌晨两点,systemctl status ffmpeg-live@event.service 终于显示绿了——那一刻我知道,剩下就是观察与优化。
1. 目标与适用场景
- 目标:在 CentOS 7 上构建一套 Nginx + FFmpeg 的一体化视频转码与分发架构,支持 点播 VOD 批量转码 与 直播 RTMP/HLS 转码,对外提供 HLS(fMP4/TS) 分发,具备横向扩展与监控告警能力。
- 适用:中小规模视频平台、活动直播落地、教育与培训平台、短期应急大促与发布会;香港机房可覆盖大陆与东南亚,时延与带宽相对友好。
- 说明:本文基于 CentOS 7 最小化安装(仍有大量存量环境),重点覆盖从系统层到服务层的可复制步骤与坑位。
2. 架构总览(文字拓扑)
上游内容 →(SFTP/对象存储/本地挂载)→ 转码节点(FFmpeg 批量/实时) →(输出 HLS 切片与索引)→ Nginx 分发层 →(HTTP/HTTPS/HTTP/2)→ 观众端播放器
可选:
- 直播推流入口使用 Nginx-RTMP 模块或外部推流网关;
- 静态分发前挂接 CDN(海外可 Cloudflare,国内可多线供应商)以扩容;
- 对象存储/分布式存储(如 MinIO、Ceph)用于长周期归档,边转边迁移。
3. 硬件与网络选型(实战参数)
3.1 推荐配置(单台 All-in-One,便于起步)
| 组件 | 选型 | 关键参数/理由 |
|---|---|---|
| CPU(CPU 转码) | Intel Xeon Silver 4210R ×2 或 AMD EPYC 7302P ×1 | 20C40T/16C32T,AVX2;x264 “veryfast” 档每核可稳跑 1080p@~0.5 路(视片源而定) |
| GPU(可选) | NVIDIA T4 ×1 | NVENC 稳定,单卡 1080p@30fps 可 6–10 路,视预设与码率而定 |
| 内存 | 64–128GB DDR4 | HLS 切片缓存与并发连接缓冲 |
| 系统盘 | SATA SSD 480GB | 系统与日志分离,降低写放大对数据盘影响 |
| 数据盘 | NVMe SSD 1.92TB ×2(RAID1) | 顺序读写 >2GB/s,随机 IOPS 高,保证切片写入与并发读取 |
| 网口 | 10GbE ×2(bond0,LACP) | 吞吐与冗余;对外 BGP 或多线接入 |
| 机房 | 香港 MEGA-i / 新世界电讯 / CITIC 等 | 机房质量与路由质量较好,跨境延迟与抖动较低 |
估算经验:CPU-only 场景,40 逻辑核约能稳跑 1080p 转码 15–20 路(veryfast),HLS 分发并发受带宽与文件句柄影响;加一张 T4,1080p 转码能力可再提升一倍以上。
3.2 带宽与并发容量粗算
码率阶梯(推荐):
| 级别 | 分辨率/帧率 | 视频码率 | 音频码率 | 典型用法 |
| 240p | 426×240@30 | 300 kbps | 64 kbps | 极弱网保底 |
| 360p | 640×360@30 | 600 kbps | 96 kbps | 标清保底 |
| 480p | 854×480@30 | 1,000 kbps | 96 kbps | 过渡档 |
| 720p | 1280×720@30 | 2,500 kbps | 128 kbps | 主力档 |
| 1080p | 1920×1080@30 | 5,000 kbps | 160 kbps | 高清 |
并发 ≈ 出口带宽(bps)/ 平均档码率。
例如:对外 5 Gbps 出口,观众平均落在 2.5 Mbps 档:
- 理论并发 ≈ 5,000 Mbps / 2.5 Mbps ≈ 2,000;
- 预留 20% 冗余与突发,稳态并发建议 1,600 左右。
4. 系统安装与基础加固(CentOS 7)
# 最小化安装后
yum -y update
yum -y install epel-release yum-utils chrony htop iotop iftop jq tmux git wget curl zip unzip bind-utils \
device-mapper-persistent-data lvm2 numactl python3 policycoreutils-python
# 时间同步
systemctl enable --now chronyd
chronyc sources -v
# 关闭不必要服务(按需保留)
systemctl disable --now postfix cups rpcbind
# 防火墙与 SELinux
yum -y install firewalld
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-port=1935/tcp # RTMP 可选
firewall-cmd --reload
# SELinux 建议保持 Enforcing,后续为 Nginx/HLS 目录添加上下文
sestatus
内核/系统参数(/etc/sysctl.d/99-video-hls.conf):
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
fs.file-max = 2097152
vm.swappiness = 10
sysctl --system
# 打开文件句柄(/etc/security/limits.d/99-nofile.conf)
echo -e "* soft nofile 1048576\n* hard nofile 1048576" > /etc/security/limits.d/99-nofile.conf
5. 磁盘与目录规划
# 数据卷:NVMe /dev/nvme0n1p1, /dev/nvme1n1p1 组 RAID1(mdadm 或硬 RAID)
mkfs.xfs /dev/md0
mkdir -p /data/{hls_vod,hls_live,upload,tmp}
# fstab 挂载示例(/etc/fstab)
/dev/md0 /data xfs noatime,nodiratime,nobarrier,logbufs=8,attr2 0 0
设置 SELinux 上下文(很容易踩坑):
semanage fcontext -a -t httpd_sys_rw_content_t "/data(/.*)?"
restorecon -Rv /data
不做这一步,Nginx/FFmpeg 在写 HLS 切片时会遇到 13 Permission denied,使你误以为是目录权限问题。
6. 安装 Nginx(含 RTMP 可选)
生产环境建议源码编译,便于开启需要的模块并绑定较新的 OpenSSL(CentOS 7 默认 1.0.2 无 TLS1.3,但 TLS1.2 足够)。
# 依赖
yum -y install gcc gcc-c++ pcre pcre-devel zlib zlib-devel openssl-devel libxml2-devel libxslt-devel \
gd-devel geoip-devel perl-ExtUtils-Embed
# 源码
cd /usr/local/src
wget https://nginx.org/download/nginx-1.24.0.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/refs/tags/v1.2.2.tar.gz -O nginx-rtmp.tar.gz
tar xzf nginx-1.24.0.tar.gz
tar xzf nginx-rtmp.tar.gz
# 编译(RTMP 模块按需,亦可省略)
cd nginx-1.24.0
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-threads \
--with-file-aio \
--with-http_stub_status_module \
--add-module=../nginx-rtmp-module-1.2.2
make -j$(nproc) && make install
ln -sf /usr/local/nginx/sbin/nginx /usr/bin/nginx
# systemd 单元
cat >/etc/systemd/system/nginx.service <<'EOF'
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
ExecStart=/usr/bin/nginx
ExecReload=/usr/bin/nginx -s reload
ExecStop=/usr/bin/nginx -s quit
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now nginx
Nginx 核心配置(/usr/local/nginx/conf/nginx.conf):
user nginx;
worker_processes auto;
pid /var/run/nginx.pid;
events {
worker_connections 65535;
multi_accept on;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
aio threads;
keepalive_timeout 65;
server_tokens off;
# 日志
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
# 缓存与打开文件优化
open_file_cache max=100000 inactive=120s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# CORS(播放器跨域)
map $request_method $cors {
default "";
~*OPTIONS 1;
}
server {
listen 80 default_server reuseport;
server_name _;
# HLS VOD 与 LIVE 目录
location /vod/ {
root /data/hls_vod;
add_header Cache-Control "max-age=60" always;
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
add_header Access-Control-Allow-Headers "*" always;
if ($cors) { return 204; }
types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; }
}
location /live/ {
root /data/hls_live;
add_header Cache-Control "no-cache" always;
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Allow-Methods "GET, OPTIONS" always;
add_header Access-Control-Allow-Headers "*" always;
if ($cors) { return 204; }
types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; }
}
# 健康与状态
location /nginx_status { stub_status; allow 127.0.0.1; allow 10.0.0.0/8; deny all; }
}
}
RTMP(直播接入,按需):在 nginx.conf 末尾追加:
rtmp {
server {
listen 1935;
chunk_size 4096;
application live {
live on;
record off;
allow publish 10.0.0.0/8; # 按需限制推流源
deny publish all;
}
}
}
坑位:如果 HLS 目录不在 /usr/local/nginx/html 下,务必做好 SELinux 上下文;另外 .m3u8 与 .ts 的 Content-Type 正确与否,直接影响部分终端的兼容性。
7. 安装 FFmpeg(源码,CPU/NVENC 两种)
7.1 基础依赖
yum -y groupinstall "Development Tools"
yum -y install autoconf automake bzip2 bzip2-devel cmake3 libtool make mercurial nasm yasm pkgconfig zlib-devel \
freetype-devel libpng-devel libjpeg-turbo-devel libwebp-devel opus-devel
alternatives --set cmake /usr/bin/cmake3
nasm 版本坑:CentOS 7 自带 nasm/yasm 过旧,容易在 libx265/libaom 编译时出错。遇到报错,先升级 nasm 至 ≥2.15(源码编译)。
7.2 第三方编解码器(按需)
# x264
cd /usr/local/src && git clone https://code.videolan.org/videolan/x264.git
cd x264 && ./configure --prefix=/usr/local --enable-static --enable-pic && make -j$(nproc) && make install
# x265
cd /usr/local/src && hg clone https://bitbucket.org/multicoreware/x265
cd x265/build/linux && cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr/local -DENABLE_SHARED=off ../../source
make -j$(nproc) && make install
# fdk-aac(非自由,按需)
cd /usr/local/src && git clone https://github.com/mstorsjo/fdk-aac.git
cd fdk-aac && autoreconf -fiv && ./configure --prefix=/usr/local --enable-static && make -j$(nproc) && make install
# libvpx(VP8/VP9)
cd /usr/local/src && git clone https://chromium.googlesource.com/webm/libvpx
cd libvpx && ./configure --prefix=/usr/local --disable-examples --disable-tools --enable-vp9-highbitdepth && make -j$(nproc) && make install
7.3 FFmpeg 编译(CPU)
cd /usr/local/src && git clone https://github.com/FFmpeg/FFmpeg.git ffmpeg-src
cd ffmpeg-src && ./configure \
--prefix=/usr/local/ffmpeg \
--pkg-config-flags="--static" \
--extra-cflags="-I/usr/local/include" \
--extra-ldflags="-L/usr/local/lib" \
--extra-libs="-lpthread -lm" \
--enable-gpl --enable-nonfree \
--enable-libx264 --enable-libx265 --enable-libfdk_aac --enable-libvpx --enable-libopus
make -j$(nproc) && make install
ln -sf /usr/local/ffmpeg/bin/ffmpeg /usr/bin/ffmpeg
ln -sf /usr/local/ffmpeg/bin/ffprobe /usr/bin/ffprobe
7.4 FFmpeg 编译(NVENC,可选)
安装 NVIDIA 驱动与 CUDA 工具包后,编译 FFmpeg 加 --enable-nvenc。CentOS 7 上建议使用官方 CUDA repo 安装驱动(确保内核匹配)。
# 在 7.3 基础上追加
./configure ... --enable-nvenc
8. 转码流水线(VOD 与 LIVE)
8.1 VOD:批量转码到 HLS(fMP4) + 自适应码率主索引
目录策略:
- 源:/data/upload(只读)
- 目标:/data/hls_vod/<slug>/<rung>/index.m3u8(rung= 240p/360p/...)
脚本(/usr/local/bin/vod-transcode.sh):
#!/bin/bash
set -euo pipefail
SRC_DIR=/data/upload
DST_DIR=/data/hls_vod
ladder=(
"240:426x240:300k:64k"
"360:640x360:600k:96k"
"480:854x480:1000k:96k"
"720:1280x720:2500k:128k"
"1080:1920x1080:5000k:160k"
)
for src in $(find "$SRC_DIR" -type f -iname "*.mp4" -o -iname "*.mov" -o -iname "*.mkv"); do
slug=$(basename "${src%.*}" | tr ' ' '-')
out="$DST_DIR/$slug"
mkdir -p "$out"
map_args=()
i=0
for rung in "${ladder[@]}"; do
IFS=":" read -r name size vbr abr <<<"$rung"
rung_out="$out/$name"
mkdir -p "$rung_out"
map_args+=( -map 0:v:0 -map 0:a:0 -c:v:0 libx264 -preset veryfast -tune zerolatency \
-vf "scale=${size}:flags=bicubic" -b:v:0 ${vbr} -maxrate:v:0 ${vbr} -bufsize:v:0 $((${vbr%k}*2))k \
-g 60 -keyint_min 60 -sc_threshold 0 -c:a:0 aac -b:a:0 ${abr} -ac 2 \
-f hls -hls_time 2 -hls_playlist_type vod -hls_flags independent_segments+single_file+append_list \
-hls_segment_type fmp4 -master_pl_name master.m3u8 -hls_segment_filename "$rung_out/seg%05d.m4s" \
"$rung_out/index.m3u8" )
((i++))
done
ffmpeg -hide_banner -y -i "$src" "${map_args[@]}"
echo "[OK] $src -> $out"
done
挂载到 Nginx:上文 /vod/ 已根指向 /data/hls_vod,访问路径示例:
http://<server>/vod/<slug>/720/index.m3u8
http://<server>/vod/<slug>/master.m3u8 # 自适应主索引
小技巧:fMP4(-hls_segment_type fmp4)在 iOS/新浏览器表现更好;若需兼容非常旧的终端,可切回 TS(删掉 -hls_segment_type 并用 seg%05d.ts)。
8.2 LIVE:RTMP 进、HLS 出,多码率实时转码
目录:/data/hls_live/<stream_key>/<rung>/index.m3u8
systemd 模板服务(/etc/systemd/system/ffmpeg-live@.service):
[Unit]
Description=FFmpeg Live Transcoder for %i
After=network.target nginx.service
[Service]
Type=simple
LimitNOFILE=1048576
ExecStart=/usr/bin/bash -lc '/usr/bin/ffmpeg -hide_banner -loglevel warning -fflags nobuffer -flags low_delay \
-rtbufsize 256M -i rtmp://127.0.0.1/live/%i \
-filter_complex "[0:v]split=5[v240][v360][v480][v720][v1080]; \
[v240]scale=426:240:flags=bicubic[v240o]; \
[v360]scale=640:360:flags=bicubic[v360o]; \
[v480]scale=854:480:flags=bicubic[v480o]; \
[v720]scale=1280:720:flags=bicubic[v720o]; \
[v1080]scale=1920:1080:flags=bicubic[v1080o]" \
-map "[v240o]" -map a:0 -c:v:0 libx264 -preset veryfast -tune zerolatency -b:v:0 300k -g 60 -keyint_min 60 -sc_threshold 0 -c:a:0 aac -b:a:0 64k -f hls -hls_time 2 -hls_list_size 6 -hls_flags delete_segments+independent_segments -hls_segment_filename /data/hls_live/%i/240/seg%%05d.ts /data/hls_live/%i/240/index.m3u8 \
-map "[v360o]" -map a:0 -c:v:1 libx264 -preset veryfast -tune zerolatency -b:v:1 600k -g 60 -keyint_min 60 -sc_threshold 0 -c:a:1 aac -b:a:1 96k -f hls -hls_time 2 -hls_list_size 6 -hls_flags delete_segments+independent_segments -hls_segment_filename /data/hls_live/%i/360/seg%%05d.ts /data/hls_live/%i/360/index.m3u8 \
-map "[v480o]" -map a:0 -c:v:2 libx264 -preset veryfast -tune zerolatency -b:v:2 1000k -g 60 -keyint_min 60 -sc_threshold 0 -c:a:2 aac -b:a:2 96k -f hls -hls_time 2 -hls_list_size 6 -hls_flags delete_segments+independent_segments -hls_segment_filename /data/hls_live/%i/480/seg%%05d.ts /data/hls_live/%i/480/index.m3u8 \
-map "[v720o]" -map a:0 -c:v:3 libx264 -preset veryfast -tune zerolatency -b:v:3 2500k -g 60 -keyint_min 60 -sc_threshold 0 -c:a:3 aac -b:a:3 128k -f hls -hls_time 2 -hls_list_size 6 -hls_flags delete_segments+independent_segments -hls_segment_filename /data/hls_live/%i/720/seg%%05d.ts /data/hls_live/%i/720/index.m3u8 \
-map "[v1080o]" -map a:0 -c:v:4 libx264 -preset veryfast -tune zerolatency -b:v:4 5000k -g 60 -keyint_min 60 -sc_threshold 0 -c:a:4 aac -b:a:4 160k -f hls -hls_time 2 -hls_list_size 6 -hls_flags delete_segments+independent_segments -hls_segment_filename /data/hls_live/%i/1080/seg%%05d.ts /data/hls_live/%i/1080/index.m3u8'
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
启动一条直播转码:
# OBS/推流器推到 rtmp://<server>/live/event
systemctl enable --now ffmpeg-live@event
# 访问: http://<server>/live/event/720/index.m3u8 或 master.m3u8(可扩展生成)
NVENC 直播:将 -c:v libx264 -preset veryfast -tune zerolatency 替换为 -c:v h264_nvenc -preset llhp -rc vbr -cq 24 -b:v <target> -maxrate <target>,同时注意 GPU 使用率与温度。
9. TLS/HTTPS(可选但推荐)
CentOS 7 环境下,使用 acme.sh 获取证书较省心:
curl https://get.acme.sh | sh
~/.acme.sh/acme.sh --issue -d example.com -w /usr/local/nginx/html
~/.acme.sh/acme.sh --install-cert -d example.com \
--key-file /usr/local/nginx/conf/ssl/example.key \
--fullchain-file /usr/local/nginx/conf/ssl/example.crt \
--reloadcmd "/usr/bin/nginx -s reload"
Nginx server 中加入:
server {
listen 443 ssl http2 reuseport;
server_name example.com;
ssl_certificate conf/ssl/example.crt;
ssl_certificate_key conf/ssl/example.key;
ssl_protocols TLSv1.2; # CentOS7 OpenSSL 1.0.2
ssl_ciphers HIGH:!aNULL:!MD5;
# ... 其余与 :80 同步的 location
}
10. 监控与可观测性
10.1 Nginx 指标与日志
- /nginx_status:当前连接、请求速率;
- access.log:结合 GoAccess 或自建 ELK,观察 HLS 命中、端到端时延与 4xx/5xx。
10.2 FFmpeg 健康度
切片“新鲜度”检查(/usr/local/bin/check-hls-freshness.sh):
#!/bin/bash
set -e
root="$1" # /data/hls_live
now=$(date +%s)
while IFS= read -r -d '' m3u8; do
ts=$(stat -c %Y "$m3u8")
age=$((now - ts))
if (( age > 20 )); then
echo "STALE: $m3u8 is $age s old"
fi
done < <(find "$root" -type f -name 'index.m3u8' -print0)
配合 */1 * * * * cron,输出到报警系统。
10.3 系统层
- node_exporter + Prometheus + Grafana:CPU、磁盘 IO、网卡流量、文件句柄;
- smartctl 监控 NVMe 健康度;
- journalctl -u ffmpeg-live@* -f:实时观察转码日志。
11. 压测与优化
11.1 文件分发压测
# wrk 对单个 .ts/.m4s 做并发压测
wrk -t8 -c2000 -d60s --latency http://<server>/vod/demo/720/seg00001.m4s
Nginx 调优要点:
- reuseport 打开,配合 worker_processes auto;
- open_file_cache 合理设置,避免频繁 stat;
- aio threads 有助于 NVMe 并发;
- 关闭对媒体的 gzip;
- sendfile on; tcp_nopush on;。
11.2 FFmpeg 调优
- GOP 与 -hls_time 对齐(30fps → -g 60 配 -hls_time 2),减少切片边界花屏;
- -max_muxing_queue_size 1024 处理复杂滤镜下的队列溢出;
- 音频全量重采样到 48kHz,-ar 48000 -ac 2,避免播放端兼容问题。
12. 线上“坑位”与解决记录
| 现象 | 根因 | 解决 |
13: Permission denied 写不进 /data/hls_* |
SELinux 上下文未赋予 | semanage fcontext + restorecon(见上) |
| 观众端偶发 404 取不到 seg | Nginx 缓存或并发下目录项延迟 | open_file_cache + NVMe,必要时增大 inotify/fs 限制 |
| 播放端切档卡顿 | GOP 与 hls_time 不匹配 |
固定帧率、-g 与 -keyint_min 一致;-sc_threshold 0 |
| 大陆用户 HTTPS 首包慢 | 海外链路与 TLS handshake | 前置 CDN,多点回源;TLS 会话复用;HTTP/2 |
Non monotonous DTS 警告 |
源流时间戳异常 | -fflags +genpts 或仅对异常源做一次重封装 |
| NVENC 质量不稳 | 预设与码控不当 | -preset p4/p5(llhq/llhp)+ -rc vbr -cq 22~26,并设合理 -maxrate |
| OBS 能推流但 FFmpeg 不启动 | RTMP 权限或地址错误 | 放开 allow publish 网段;检查 application 名与 stream key |
13. 扩展与演进
- 对象存储分层:转码完成的 VOD 自动同步至 MinIO/Ceph,Nginx 用 proxy_cache 或 s3 gateway 回源;
- 多机房:香港主、海外/内地边缘分发,使用主动健康检查与 GeoDNS;
- DASH 支持:并行产出 .mpd,浏览器端 ExoPlayer/Shaka 播放;
- 自动化:Ansible/Terraform 声明式部署;
- 熔断保护:live 路径切片“新鲜度”超阈值自动切换备用源。
14. 成本核算(样例)
| 项目 | 数量 | 单价(HKD/月) | 小计 |
| 物理服务器(双 10GbE, NVMe×2) | 1 | 3,800 | 3,800 |
| 带宽(专线 5Gbps 95 计费) | 1 | 9,500 | 9,500 |
| 机柜/电力(1/4 柜) | 1 | 2,000 | 2,000 |
| 证书/CDN(可选) | - | 视流量 | - |
| 合计(不含税) | 约 15,300+ |
实际价格与合约相关,上述仅作预算参考。
15. 附:完整示例配置清单
15.1 nginx.conf(简版可用)
已在第 6 节给出;生产环境建议将 server 与 http 片段分拆,使用 include conf.d/*.conf。
15.2 systemd 服务
- /etc/systemd/system/nginx.service
- /etc/systemd/system/ffmpeg-live@.service
15.3 脚本
- /usr/local/bin/vod-transcode.sh
- /usr/local/bin/check-hls-freshness.sh
赋予执行权限:chmod +x,并用 tmux/screen 观察首次跑批日志。
16. 尾声:一次凌晨的“回放”
上线当天晚上 23:47,我坐在机房的冷通道口,手背被主机前面板的风吹到发凉。wrk 压测曲线稳定在我们预期值,Grafana 面板上的 95 线延迟稳稳落在 40ms 以下。凌晨 00:10,客户发来第一条观众截图:在厦门 4G 环境下 720p 流畅播放。我看了一眼 journalctl 里滚动的 FFmpeg 日志,又把机柜门关上,听着门锁“咔哒”一声落位——这套在 CentOS 7 上打磨出来的 Nginx + FFmpeg 一体化架构,总算在这个夜里通过了它的第一场考验。