✏️ 编辑

视频服务运维故障排查 · 完整知识体系

创建于 2026-07-02 10:45:18 · 更新于 2026-07-02 16:01:27

视频服务运维故障排查 · 完整知识体系

学习日期:2026-07-02
涵盖11个常见故障场景,从概念到命令,从排查思路到解决方案


一、基础知识

FFprobe 速查

FFprobe 是 FFmpeg 全家桶中的视频文件"体检仪"。

命令 作用
ffprobe -v error file.mp4 静默检查文件是否损坏(无输出=正常)
ffprobe -v error -show_entries stream=codec_name,width,height file.mp4 查看视频编码、分辨率
ffprobe -v error -show_entries stream=codec_type,codec_name,width,height -of json file.mp4 JSON格式输出(最常用)
ffprobe -v error -show_entries stream=index,codec_type,duration -of json file.mp4 对比音视频时长

JSON输出示例:

JSON
{
  "streams": [
    {"codec_type": "video", "codec_name": "h264", "width": 1920, "height": 1080},
    {"codec_type": "audio", "codec_name": "aac"}
  ]
}
字段 含义
codec_type "video"=视频流, "audio"=音频流
codec_name h264 / hevc / vp9 等编码格式
width / height 视频分辨率

转码概念

转码 = 把用户上传的原始视频转换成服务器统一标准格式的过程。

用户上传(千奇百怪)                转码后(统一标准)
MOV / H.265 / 4K        ——→        MP4 / H.264 / 1080p
                                    + 720p 版本
                                    + 480p 版本
                                    + 封面图

为什么要转码:
- 格式统一:不同浏览器/设备支持不同的格式
- 兼容性:H.264 是所有浏览器都支持的编码
- 多码率:根据用户网速自动切换清晰度
- 封面图:从视频中抽取首帧生成

转码排查三件套

Bash
# ① 文件大小——是不是0KB?
ls -lh uploads/video.mov

# ② ffprobe检查
ffprobe -v error uploads/video.mov

# ③ 看真实文件类型(不看后缀)
file uploads/video.mov

二、播放质量类

场景①:视频黑屏/加载不出来

工单特征: 一个视频黑屏,其他视频正常,文件存在。

排查流程:

用户反馈视频无法播放
    │
    ├─ 其他视频也异常? → 全局问题(服务/CDN)
    │
    └─ 只有这个视频? → 聚焦文件本身
          │
          ├─ ffprobe 检查视频流
          │   ├── 无视频流(只有音频)→ 转码失败/上传了错误文件
          │   ├── 编码浏览器不支持(HEVC/H.265)→ 转码兼容格式 H.264
          │   ├── 文件损坏 → 重新上传转码
          │   └── 视频正常 → 查播放器/协议/CDN
          │
          └─ file 命令确认真实文件类型

常见编解码兼容性:

编码 浏览器兼容性
H.264 (AVC) 所有浏览器 ✅
H.265 (HEVC) Safari ✅, Chrome/Edge ⚠️ 部分支持
VP9 Chrome/Firefox/Edge ✅, Safari ❌

场景②:播放卡顿、频繁缓冲

工单特征: 晚8~10点卡顿,白天正常。

核心判断: 高峰期带宽瓶颈。

排查流程:

高峰期卡顿
    │
    ├─ 查带宽监控(云监控 / iftop / sar -n DEV 1 3)
    │   ├── 带宽没打满 → 查 CPU/IO/连接数
    │   └── 带宽打满 ✓ → 带宽瓶颈
    │         │
    │         ├─ 没接 CDN → 建议上 CDN
    │         │
    │         └─ 有 CDN → 查 CDN 命中率(curl -I 看 X-Cache 头)
    │               │
    │               ├─ HIT 高 → 正常流量暴涨
    │               │
    │               └─ 大量 MISS → 排查四个方向:
    │                    ① TTL 太短 → 加长(视频推荐 7~30 天)
    │                    ② cache_key 参数不同 → 忽略 URL 参数
    │                    ③ 没做预热 → 上线前预热
    │                    ④ 大文件分片回源 → 改用 HLS 切片

紧急止血:

Nginx
# Nginx 限速限连接
limit_rate 1M;
limit_conn addr 1;

# CDN 带宽封顶(云厂商控制台)

视频资源合理 TTL:
- 视频文件 (.mp4/.ts) → 7~30 天
- 封面图/缩略图 → 3~7 天
- 字幕文件 (.vtt) → 1~7 天
- HLS m3u8 索引文件 → 2~5 秒(直播场景特殊)

场景③:音画不同步

工单特征: 画面和声音对不上,且越往后延迟越严重。

根因: 转码时帧率参数错误(如源文件 24fps 被设成 30fps),导致时间戳逐帧偏移累加。

排查方法:

Bash
ffprobe -v error -show_entries stream=index,codec_type,duration -of json video.mp4
# 对比视频流和音频流的总时长是否一致

# 如果视频 5400s,音频 5398.5s
# → 视频比音频长 1.5s,到结尾时音画差 1.5 秒

修复:

Bash
ffmpeg -i input.mp4 -c:v libx264 -r 24 -c:a copy output.mp4
# 锁定正确帧率重新编码视频流,音频流直接复制

三、缓存与 CDN 类

CDN 三兄弟(核心概念)

操作 做什么 场景
🔄 刷新 (Purge) 删除 CDN 缓存,下次请求回源拉新 内容更新了(紧急修复)
🔥 预热 (Preload) 主动把资源推到 CDN 节点 新内容上线前(提前缓存)
🚫 封禁 (Block) 禁止 URL 通过 CDN 访问 资源下架/违规内容

CDN MISS 四个排查方向

  1. TTL 太短:缓存时间短导致频繁回源
  2. cache_key 参数问题:URL 带随机参数(如 ?t=timestamp)导致每次都是 MISS
  3. 没做预热:新资源上线没提前推到 CDN 节点
  4. 大文件分片回源:超大文件无法完整缓存,Range 请求穿透

场景④:缓存未更新

工单特征: 后台改了封面图/标题,用户看到还是旧的。

排查流程:

"封面图还是旧的"
    │
    ├─ 无痕窗口 / Ctrl+F5 强制刷新
    │   └── 能解决 → 浏览器缓存 ✅
    │
    ├─ curl -I 看 X-Cache
    │   └── HIT → CDN 缓存了旧的
    │       └── curl 直达源站(绕 CDN)
    │           ├── 源站已更新 → CDN 需要刷新
    │           └── 源站未更新 → 找后端
    │
    └─ 解决方案对比:
        ├── 改名重新上传(最彻底,需改前端代码)
        ├── CDN 控制台刷新(紧急修复,即时生效)
        └── 等 TTL 过期(不推荐)

场景⑤:CDN 预热/刷新策略

周更剧集运维节奏参考:
- 周三:转码完成,上传到源站
- 周四 14:00:预热到 CDN 节点(留6小时同步)
- 周四 20:00:用户直接 HIT ✅
- 随时:如果运营要求替换内容 → 刷新对应 URL

旧视频一般保留,不封禁(用户可能需要回看往期内容)。

场景⑥:突发带宽飙升

工单特征: 带宽从 100Mbps 几分钟飙到近 1Gbps。

核心原则:先保护,再排查。 犹豫的每一秒都在烧钱(云厂商按 GB 计费)。

紧急保护:
- CDN 控制台设带宽封顶阈值
- Nginx 限速/限连接

排查方法:

Bash
# 按流量大小排序,看什么 URL 消耗带宽最多
#head -1 /var/log/nginx/access.log
awk '{print $7, $10}' /var/log/nginx/access.log | \
  awk '{sum[$1]+=$2} END {for(u in sum) printf "%.2f MB %s\n", sum[u]/1024/1024, u}' | \
  sort -rn | head -10
#{print $7, $10} 从原始日志里挑出"URL路径"和"字节数"两列;{sum[$1]+=$2} 针对这两列,按URL分组累加字节数

三看判断法:
1. 流量集中在 1~2 个 URL → 视频突然火了(正常)
2. 流量分散在大量 URL → 爬虫/CC 攻击
3. 请求集中在非视频路径(如 /api/)→ 异常攻击

扩容不是第一选择,先排查优化方向。

场景⑦:热点视频导致源站压力大

工单特征: CDN 命中率高、带宽正常,但源站 CPU/连接数爆了。

关键发现: 动态 API 不能被 CDN 缓存。

Bash
# 按请求次数统计(不是按流量)
awk '{print $7}' /var/log/nginx/access.log | \
  sort | uniq -c | sort -rn | head -10

动态接口能否缓存?
- 所有人返回的数据一样 → ✅ 能加 Redis / Nginx 缓存
- 每人每次返回不同(如播放 token)→ ❌ 不能缓存,改用限流/扩容

Python
# Redis 缓存示例(伪代码)
def get_video_info(video_id):
    cache_key = f"video:info:{video_id}"
    data = redis.get(cache_key)
    if data:
        return data  # 直接返回,不查数据库
    data = db.query("SELECT * FROM videos WHERE id=?", video_id)
    redis.setex(cache_key, 300, data)  # 缓存5分钟
    return data

四、上传与处理类

场景⑧:上传失败/超时

工单特征: 2GB 大文件上传到 80% 失败,小文件正常。

三层超时排查:

用户浏览器 → Nginx → 应用服务器 (Flask/Gunicorn)
  默认 60s    proxy_read_timeout 60s    Gunicorn timeout 30s
Nginx
# Nginx 上传配置
client_max_body_size 5G;        # 文件大小上限
proxy_read_timeout 600s;        # 读超时
proxy_send_timeout 600s;        # 写超时
proxy_request_buffering off;    # 关缓冲(大文件)

** HTTP 错误码速查:**
- 413 Request Entity Too Large → client_max_body_size 太小
- 504 Gateway Timeout → proxy_read_timeout 超时
- 502 Bad Gateway → 应用进程挂了

最佳实践: 分片上传 + 断点续传,而不是单纯调超时。

场景⑨:转码失败

工单特征: 用户上传 MOV 视频,转码状态:失败。报错 Invalid data found when processing input

报错含义: FFmpeg 读不懂这个文件。

常见原因:
- 文件损坏(上传中断,只传了一半)
- 格式伪装(文件名是 .mp4,实际是 HTML 或其他)
- 空文件(0KB)
- 加密 / DRM 保护
- 编码器不支持(罕见冷门格式)

排查:

Bash
# ① 文件大小
ls -lh uploads/video.mov

# ② ffprobe 检查
ffprobe -v error uploads/video.mov

# ③ 看真实文件类型
file uploads/video.mov
# 正常输出:ISO Media, Apple QuickTime movie
# 异常输出:HTML document, UTF-8 Unicode text(实际上是网页)

五、平台兼容类

场景⑩:部分用户能看,部分不能

工单特征: 北京/上海正常,广东/四川看不了。文件、转码、CDN 配置都正常。

根因: 特定地区 CDN 节点故障 / 跨运营商 / DNS 解析错误。

排查方法:

Bash
# 伪造来源 IP,模拟不同地区用户
curl -H "X-Forwarded-For: 广东IP地址" -I https://cdn.example.com/video.mp4
# X-Forwarded-For 是 HTTP 头,用来标识原始请求 IP
# CDN 会根据这个头判断用户来源,分配对应区域的节点
# -I 只返回响应头,不下载正文

# 补充排查
ping cdn.example.com         # 看 DNS 解析是否正确
traceroute cdn.example.com   # 看网络路径

可能原因与解决:
- CDN 节点宕机 → 联系 CDN 厂商
- 跨运营商(电信/联通/移动)→ 上全网 CDN 或 BGP
- DNS 解析到错误 IP → 检查 DNS 配置,等 TTL 刷新

场景⑪:某些浏览器/设备播放异常

工单特征: Chrome 黑屏但有声音,Safari 正常。

根因: 视频编码不被 Chrome 支持(如 H.265)。

各浏览器编码支持:

浏览器 H.264 H.265 VP9
Chrome ⚠️ 部分
Safari
Firefox ⚠️ 部分
Edge ⚠️ 部分

解决方案: 转码一份 H.264 版本作为兼容格式。


六、常用排查命令汇总

文件检查

Bash
ffprobe -v error -show_entries stream=codec_name,width,height -of json video.mp4
file video.mp4
ls -lh video.mp4

CDN 检查

Bash
curl -I https://cdn.example.com/video.mp4                  # 看 X-Cache 状态
curl -H "X-Forwarded-For: 地区IP" -I URL                   # 模拟地区请求

服务器负载

Bash
top                       # CPU
iftop -i eth0             # 实时带宽
sar -n DEV 1 3            # 网卡流量统计

日志分析

Bash
# 按请求次数排序
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -10

# 按流量大小排序(字节转 MB)
awk '{print $7, $10}' access.log | \
  awk '{sum[$1]+=$2} END {for(u in sum) printf "%.2f MB %s\n", sum[u]/1024/1024, u}' | \
  sort -rn | head -10

转码

Bash
ffmpeg -i input.mov -c:v libx264 -c:a aac output.mp4

七、核心排查思维

  1. 先保护,再排查 — 突发状况(带宽飙高)先止血,再慢慢找原因
  2. 先优化,再扩容 — 扩容是最后手段,不是第一选择
  3. 先局部,再全局 — 一个文件有问题?先看文件本身,别先怀疑整个服务
  4. 变更前先沟通确认 — 改参数前问清楚影不影响其他业务,跟相关方确认

八、涉及的核心概念对比

视频编码

  • H.264 (AVC):兼容性最好,所有浏览器/设备都支持。视频服务的默认选择。
  • H.265 (HEVC):压缩率更高(同样画质体积减半),但浏览器支持不完整。适合 4K/8K 内容,需额外做兼容格式。
  • VP9:Chrome 系浏览器原生支持的开源编码。

浏览器缓存 vs CDN 缓存

  • 浏览器缓存:存在用户本地。解决方式:Ctrl+F5 强制刷新 / 无痕窗口。
  • CDN 缓存:存在 CDN 节点上。解决方式:CDN 控制台刷新 / 改文件名重发。

CDN 三兄弟

  • 刷新:删除已有缓存,让下次请求回源拉新的。
  • 预热:主动把资源推到 CDN 节点存好。
  • 封禁:禁止 URL 访问(返回 403)。

突发带宽 vs 源站压力

  • 突发带宽:带宽指标飙高。根因可能是 CDN 策略/攻击/正常流量。查带宽监控、X-Cache。
  • 源站压力:CPU/连接数飙高但带宽正常。根因通常是动态 API 被打爆。查请求次数、接口能缓存吗。

ffprobe 常见输出解读

  • codec_name=h264 → 正常,兼容性好
  • codec_name=hevc → H.265,注意浏览器兼容
  • 只有 audio 没有 video → 不是视频文件或转码出问题
  • ffprobe 报错 → 文件损坏或格式不对