添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接


我第一次把 GPU 转码落到香港机房,RTMP 推流峰值把 CPU 干到了 95% 以上,告警像鞭炮一样一串串炸。楼上运维在抱怨冷气机结霜,我蹲在 42U 柜前,看着 top 里疯狂跑满的 ffmpeg 进程,心里只有一句话:该把活儿交给 GPU 了。

这篇文章,把那一夜以来我在香港节点做 GPU 转码的实操、坑点和优化,完整复刻出来——尽量做到新手能照抄跑起来,老手能看懂细节与取舍。

一、目标与总览架构

  • 把解码+转码从 CPU 挪到 GPU(NVDEC+NVENC),把 CPU 从 80%+ 压到 20% 以下;
  • 支撑高并发推流(RTMP/SRT/WHIP),并发路数、码级组合可水平扩展;
  • 产出多码率(ABR)HLS/FLV,延迟与画质在可接受区间内(直播场景优先低延迟)。
  • 参考架构(文本示意):

    [Ingest层: SRS/NGINX-RTMP多实例]  <--RTMP/SRT/WebRTC推流--
               | 通过本地Unix或TCP转发(内网)    
    [Transcode层: FFmpeg + NVENC(L4/T4等)] --ABR HLS/FLV--> [Delivery层: NGINX静态/HLS]
               +--> 监控: node_exporter + DCGM Exporter + 日志

    选型说明:我更偏向 SRS 做 Ingest(原生支持 SRT/WHIP,转发灵活),NGINX 做分发(HLS/FLV),FFmpeg 通吃转码。解耦后扩容简单,遇到 GPU 故障也容易旁路切 CPU 兜底。

    二、硬件与网络选型(香港机房落地)

    注意:香港机房路由多变,SRT 更抗抖动。公网上行推流建议优先 SRT,其次 RTMP。

    三、系统环境(CentOS 7)与前置准备

    用户要求 CentOS 7,我也确实在 CentOS 7 上跑过。但提醒:CentOS 7 已 EOL,新项目建议 AlmaLinux 8/9。本文仍给出 CentOS 7 可行路径。

    基础包与内核头文件

    yum install -y epel-release
    yum groupinstall -y "Development Tools"
    yum install -y gcc gcc-c++ make git wget pciutils \
                   kernel-devel-$(uname -r) kernel-headers-$(uname -r) \
                   cmake nasm yasm pkgconfig

    禁用 nouveau,准备安装 NVIDIA 驱动

    cat >/etc/modprobe.d/blacklist-nouveau.conf <<'EOF'
    blacklist nouveau
    options nouveau modeset=0
    dracut --force
    reboot

    安装 NVIDIA 驱动(ELRepo 稳定)

    ELRepo 的 kmod-nvidia 在 CentOS 7 上更省心:

    yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
    yum install -y nvidia-detect
    nvidia-detect
    # 按提示安装对应驱动,常见为:
    yum --enablerepo=elrepo-kernel install -y kmod-nvidia nvidia-x11-drv nvidia-driver
    reboot
    nvidia-smi

    (可选)安装 NVIDIA Container Toolkit(若用容器化)

    distribution=rhel7
    curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | tee /etc/yum.repos.d/nvidia-docker.repo
    yum install -y nvidia-docker2 && systemctl restart docker

    四、FFmpeg(启用 NVENC/NVDEC)编译安装

    CentOS 7 官方 FFmpeg 太老,基本都自行编译。以下是能稳定跑 NVENC/NVDEC 的组合。

    安装 nv-codec-headers

    git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
    cd nv-codec-headers && make && make install && cd ..

    准备第三方库(选用)

    yum install -y openssl-devel librtmp-devel \
                   libx264-devel libx265-devel \
                   libsrt-devel
    # 若仓库中无对应devel,请自行编译 x264/x265/SRT

    编译 FFmpeg(4.4/5.x 在 CentOS 7 更常见)

    git clone https://github.com/FFmpeg/FFmpeg.git
    cd FFmpeg && git checkout n5.1 # 或 n4.4 稳定分支
    ./configure --prefix=/usr/local/ffmpeg \
      --pkg-config-flags="--static" \
      --extra-cflags="-I/usr/local/include" \
      --extra-ldflags="-L/usr/local/lib" \
      --enable-gpl --enable-nonfree \
      --enable-openssl \
      --enable-libx264 --enable-libx265 \
      --enable-libsrt \
      --enable-cuda-nvcc --enable-nvenc \
      --enable-cuvid
    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
    ffmpeg -hwaccels

    兼容提示:

  • 在 FFmpeg 5.x,推荐用 -hwaccel cuda -hwaccel_output_format cuda 搭配 scale_npp;
  • 在 4.x 上 h264_cuvid/hevc_cuvid 更常见。两种写法我都给出。
  • 五、Ingest:SRS/NGINX-RTMP 二选一

    方案 A:SRS(支持 RTMP/SRT/WHIP)

    简化配置 srs.conf(仅关键片段):

    listen              1935;
    max_connections     100000;
    vhost __defaultVhost__ {
        # RTMP 推流
        ingest rtmp {
            enabled     on;
            input {
                type    stream;
                url     rtmp://0.0.0.0:1935/live?vhost=__defaultVhost__;
        # SRT 监听(更抗抖动)
        srt_server {
            enabled on;
            listen 10080;
        # 转发到转码层(内网)
        forward {
            enabled on;
            destination 10.10.10.50:1935;
    

    方案 B:NGINX-RTMP(轻量经典)

    yum install -y nginx
    git clone https://github.com/arut/nginx-rtmp-module.git
    # 源码编译 nginx 加上 rtmp 模块(略),或安装带 rtmp 的打包版

    nginx.conf 片段:

    rtmp {
        server {
            listen 1935;
            chunk_size 4096;
            application live {
                live on;
                record off;
                # 推到转码层(内网)
                push rtmp://10.10.10.50:1935/trans;
    

    六、Transcode:FFmpeg + NVENC/NVDEC(单路→多码率)

  • 通过内网从 Ingest 拉一路源(RTMP/SRT);
  • GPU 解码(NVDEC)→ scale_npp 多分辨率 → NVENC 多档码率;
  • 输出 HLS(或 FLV/LL-HLS/Chunked-TS),再由 NGINX 分发。
  • A. 现代写法(FFmpeg 5.x)

    ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -threads 1 \
      -rtbufsize 256M -fflags nobuffer -flags low_delay \
      -i "rtmp://10.10.10.40:1935/live/stream001" \
      -filter_complex "\
         [0:v]split=3[v1080][v720][v480]; \
         [v1080]scale_npp=1920:1080:interp_algo=super:format=nv12[v108o]; \
         [v720] scale_npp=1280:720:interp_algo=super:format=nv12[v720o]; \
         [v480] scale_npp=854:480:interp_algo=super:format=nv12[v480o]" \
      -map "[v108o]" -map 0:a:0 -c:v h264_nvenc -preset p5 -tune hq -rc vbr_hq \
        -b:v 5200k -maxrate 6000k -bufsize 10M -g 120 -bf 2 -spatial_aq 1 -aq-strength 8 \
        -c:a aac -b:a 160k -ar 44100 -ac 2 \
        -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments \
        -method PUT "/var/www/hls/stream001/1080p/prog_index.m3u8" \
      -map "[v720o]" -map 0:a:0 -c:v h264_nvenc -preset p5 -tune ll -rc vbr_hq \
        -b:v 2800k -maxrate 3200k -bufsize 6M -g 120 -bf 2 -spatial_aq 1 -aq-strength 10 \
        -c:a aac -b:a 128k -ar 44100 -ac 2 \
        -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments \
        -method PUT "/var/www/hls/stream001/720p/prog_index.m3u8" \
      -map "[v480o]" -map 0:a:0 -c:v h264_nvenc -preset p4 -tune ll -rc vbr_hq \
        -b:v 1200k -maxrate 1500k -bufsize 3M -g 120 -bf 2 -spatial_aq 1 -aq-strength 12 \
        -c:a aac -b:a 96k -ar 44100 -ac 2 \
        -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments \
        -method PUT "/var/www/hls/stream001/480p/prog_index.m3u8"
  • -hwaccel_output_format cuda + scale_npp 会走 GPU 上的 resize(省 CPU);
  • -tune ll/-tune hq 视延迟/质量取舍;
  • HLS 切片缩到 2s,兼顾延迟与稳定;
  • 多路映射让一进多出,减少解码开销。
  • B. 经典写法(FFmpeg 4.x,CUVID 解码)

    ffmpeg -hide_banner -c:v h264_cuvid -surfaces 16 -extra_hw_frames 8 \
      -i "rtmp://10.10.10.40:1935/live/stream001" \
      -filter_complex "\
         [0:v]split=3[v1080][v720][v480]; \
         [v1080]scale_npp=1920:1080:format=nv12[v108o]; \
         [v720] scale_npp=1280:720:format=nv12[v720o]; \
         [v480] scale_npp=854:480:format=nv12[v480o]" \
      -map "[v108o]" -map 0:a:0 -c:v h264_nvenc -preset p5 -rc vbr_hq -cq 23 -g 120 \
        -c:a aac -b:a 160k -f flv "rtmp://127.0.0.1:1935/abrlive/stream001_1080" \
      -map "[v720o]"  -map 0:a:0 -c:v h264_nvenc -preset p5 -rc vbr_hq -cq 24 -g 120 \
        -c:a aac -b:a 128k -f flv "rtmp://127.0.0.1:1935/abrlive/stream001_720" \
      -map "[v480o]"  -map 0:a:0 -c:v h264_nvenc -preset p4 -rc vbr_hq -cq 25 -g 120 \
        -c:a aac -b:a 96k  -f flv "rtmp://127.0.0.1:1935/abrlive/stream001_480"

    七、HLS/分发 NGINX 配置

    worker_processes auto;
    worker_rlimit_nofile 1048576;
    events {
        worker_connections 65535;
        use epoll;
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile      on;
        tcp_nopush    on;
        aio           threads;
        open_file_cache max=100000 inactive=20s;
        server {
            listen 80;
            server_name _;
            root /var/www/hls;
            location /hls/ {
                types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; }
                add_header Cache-Control no-cache;
            location /live.flv {
                flv_live on;  # 若使用 nginx-http-flv-module
    

    八、GPU 资源规划与算力估算(经验值)

    编码 H.264 预设 单卡 1080p30 转码路数(3码级 ABR)

    说明:单路 1080p→ABR(1080/720/480) 约等价 3 路 NVENC 的复杂度;内容复杂度(运动、纹理)会显著影响路数。

    CPU 仅做音频与封装,通常 16C 就能扛数十路 ABR。

    九、系统调优(网络、文件句柄、IRQ)

    /etc/sysctl.d/99-live.conf:

    fs.file-max = 2097152
    net.core.netdev_max_backlog = 250000
    net.core.somaxconn = 65535
    net.core.rmem_max = 134217728
    net.core.wmem_max = 134217728
    net.ipv4.ip_local_port_range = 10240 65535
    net.ipv4.tcp_max_syn_backlog = 262144
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_fin_timeout = 15
    net.ipv4.tcp_syncookies = 1
    sysctl --system
    ulimit -n 1048576

    NIC & IRQ 建议

  • 开 irqbalance,多队列 NIC 绑定中断到不同 CPU(NUMA 亲和);
  • ethtool -G eth0 rx 4096 tx 4096 适度增大环形缓冲;
  • Ingest/Delivery 节点开启 reuseport,消化大量连接。
  • 十、进程编排与多卡绑定

    多卡绑定:用 CUDA_VISIBLE_DEVICES 最稳:

    # 绑定到第0号物理卡
    CUDA_VISIBLE_DEVICES=0 ffmpeg ... # your pipeline
    # 绑定到第1号物理卡
    CUDA_VISIBLE_DEVICES=1 ffmpeg ...

    或 FFmpeg 指定 -gpu 0/1(不同版本支持差异,推荐 CUDA_VISIBLE_DEVICES)。

    Systemd 服务化(示例 one stream → three variants):

    [Unit]
    Description=FFmpeg GPU Transcode stream001
    After=network.target
    [Service]
    Environment=CUDA_VISIBLE_DEVICES=0
    ExecStart=/usr/local/ffmpeg/bin/ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -threads 1 \
      -rtbufsize 256M -fflags nobuffer -i rtmp://10.10.10.40:1935/live/stream001 \
      -filter_complex "[0:v]split=3[v1080][v720][v480];[v1080]scale_npp=1920:1080:format=nv12[v108o];[v720]scale_npp=1280:720:format=nv12[v720o];[v480]scale_npp=854:480:format=nv12[v480o]" \
      -map "[v108o]" -map 0:a:0 -c:v h264_nvenc -preset p5 -rc vbr_hq -b:v 5200k -maxrate 6000k -bufsize 10M -g 120 -c:a aac -b:a 160k \
      -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments /var/www/hls/stream001/1080p/prog_index.m3u8 \
      -map "[v720o]"  -map 0:a:0 -c:v h264_nvenc -preset p5 -rc vbr_hq -b:v 2800k -maxrate 3200k -bufsize 6M  -g 120 -c:a aac -b:a 128k \
      -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments /var/www/hls/stream001/720p/prog_index.m3u8 \
      -map "[v480o]"  -map 0:a:0 -c:v h264_nvenc -preset p4 -rc vbr_hq -b:v 1200k -maxrate 1500k -bufsize 3M  -g 120 -c:a aac -b:a 96k  \
      -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments /var/www/hls/stream001/480p/prog_index.m3u8
    Restart=always
    RestartSec=3
    LimitNOFILE=1048576
    [Install]
    WantedBy=multi-user.target

    十一、监控与告警

  • GPU:nvidia-smi dmon -s pucvmet、DCGM Exporter → Prometheus/Grafana;
  • 系统:node_exporter、nginx-vts/rtmp 统计;
  • FFmpeg:-progress pipe:1 + 解析 QPS/帧率/丢帧;
  • 告警:GPU 利用率 > 85% 持续 3 分钟、NVENC 编码失败率 > 0.5%、丢帧 > 1%。
  • 十二、压测方法(可复现)

    本地循环推流 100 路(示例素材 30fps):

    for i in $(seq -w 1 100); do
      ffmpeg -re -stream_loop -1 -i sample_1080p30.mp4 \
        -c copy -f flv "rtmp://ingest.local:1935/live/stream$i" \
        >/dev/null 2>&1 &
    

    观察 CPU/GPU:

  • GPU:watch -n1 nvidia-smi
  • CPU:htop
  • HLS 切片目录增长是否平稳,播放器连播是否不卡段。

    十三、常见坑与现场解法

    No NVENC capable devices found 驱动版本与 nv-codec-headers/FFmpeg 不匹配;容器内没挂载 /dev/nvidia* 统一驱动+headers 版本;Docker 加 --gpus all Device busy / 编码器繁忙 同卡并发路数超上限、预设过重 降 preset/rc-lookahead,分摊到另一张卡 cuvid: no decoder surfaces 解码队列不足 增 -surfaces-extra_hw_frames HLS 播放卡段 切片时间与 GOP 不匹配;磁盘 IOPS 不足 -g 约等于 fps*segment_time;SSD or tmpfs CPU 仍很高 scale 走了 CPU;音频滤镜开销 使用 scale_npp;音频尽量直通或轻量化 香港公网抖动大 RTT 抖动/丢包 换 SRT 推流(设置 latency=120200ms
  • 转码层挂了:Ingest 层临时直推 原始码流 给播放器(降级无 ABR);
  • 单卡炸了:Systemd Unit 自动拉起,Prometheus 告警触发把该流迁到其他卡;
  • HLS 出错:回滚到 FLV 直出(延迟更低,靠边缘节点抗抖)。
  • 十七、可直接复用的启动脚本(多流批量)

    /opt/transcode/run_stream.sh

    #!/usr/bin/env bash
    set -euo pipefail
    STREAM_ID="$1"            # e.g. stream001
    SRC_URL="rtmp://10.10.10.40:1935/live/${STREAM_ID}"
    OUT_DIR="/var/www/hls/${STREAM_ID}"
    mkdir -p "${OUT_DIR}"/{1080p,720p,480p}
    exec ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -threads 1 \
      -fflags nobuffer -rtbufsize 256M -i "${SRC_URL}" \
      -filter_complex "\
         [0:v]split=3[v1080][v720][v480]; \
         [v1080]scale_npp=1920:1080:format=nv12[v108o]; \
         [v720] scale_npp=1280:720:format=nv12[v720o]; \
         [v480] scale_npp=854:480:format=nv12[v480o]" \
      -map "[v108o]" -map 0:a:0 -c:v h264_nvenc -preset p5 -rc vbr_hq -b:v 5200k -maxrate 6000k -bufsize 10M -g 120 -bf 2 -spatial_aq 1 -aq-strength 8 \
        -c:a aac -b:a 160k -ar 44100 -ac 2 -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments \
        "${OUT_DIR}/1080p/prog_index.m3u8" \
      -map "[v720o]"  -map 0:a:0 -c:v h264_nvenc -preset p5 -rc vbr_hq -b:v 2800k -maxrate 3200k -bufsize 6M  -g 120 -bf 2 -spatial_aq 1 -aq-strength 10 \
        -c:a aac -b:a 128k -ar 44100 -ac 2 -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments \
        "${OUT_DIR}/720p/prog_index.m3u8" \
      -map "[v480o]"  -map 0:a:0 -c:v h264_nvenc -preset p4 -rc vbr_hq -b:v 1200k -maxrate 1500k -bufsize 3M  -g 120 -bf 2 -spatial_aq 1 -aq-strength 12 \
        -c:a aac -b:a 96k  -ar 44100 -ac 2 -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments+independent_segments \
        "${OUT_DIR}/480p/prog_index.m3u8"

    批量跑(每卡 10 路示例):

    export CUDA_VISIBLE_DEVICES=0
    for i in $(seq -w 1 10); do
      /opt/transcode/run_stream.sh "stream${i}" >/var/log/ffmpeg_stream${i}.log 2>&1 &
    

    十八、额外加分:HEVC、低延迟与 SRT

  • HEVC(h265_nvenc):比特率可降 30% 左右,但终端兼容度要看业务;
  • 低延迟:-tune ll、GOP 短、HLS part/LL-HLS 或直接走 FLV/WebRTC;
  • SRT 推流:

    srt://your_ip:10080?mode=caller&latency=150&streamid=live/stream001

    服务端 SRS 配 srt_server,公网抖动时更稳。

    后来我们把香港的 GPU 集群做成了模板:Ingest 按连接扩、Transcode 按码级扩、Delivery 按带宽扩。那台先上车的 T4,贴着我手写的标签“夜班英雄一号”。
    直播平台的高并发,跟午夜机房的风一样,时大时小。把 CPU 的苦活脏活交给 GPU,我们从此再也没被凌晨的告警吓醒。
    如果你也正要在香港节点落 GPU 转码,希望这篇实操能让你少绕点路。哪怕风再大,只要切得稳,画面就不会抖。

    快速清单(拿去即用)

    ✅ CentOS 7 裸机:ELRepo 装 NVIDIA 驱动(470LTS/匹配卡)

    ✅ 编译 FFmpeg(启用 --enable-nonfree --enable-nvenc --enable-cuvid/--hwaccel cuda)

    ✅ Ingest 用 SRS(RTMP/SRT),转发到转码层内网

    ✅ FFmpeg:NVDEC 解码 + scale_npp + NVENC 多码率

    ✅ NGINX 分发 HLS(2s 切片、independent_segments)

    ✅ ulimit、sysctl、NIC/IRQ 调优

    ✅ DCGM/Grafana 盯 GPU,nvidia-smi 看温度与功耗

    ✅ 预案:GPU 故障→旁路直出原始码流,或迁移到其他卡

    上一篇:手游服务器部署在香港机房:如何把 CN2/CMIN2/CU/PCCW 四线 BGP 配到“稳,又快”的地步,避免跨境运营商链路波动? 下一篇:如何在搭载Platinum 8352Y、512GB内存和4TB NVMe SSD的香港服务器上部署高并发跨境电商平台?(CentOS 7 系统配置详细教程)