视频服务运维故障排查 · 完整知识体系
视频服务运维故障排查 · 完整知识体系
学习日期: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输出示例:
{
"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 是所有浏览器都支持的编码
- 多码率:根据用户网速自动切换清晰度
- 封面图:从视频中抽取首帧生成
转码排查三件套
# ① 文件大小——是不是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 限速限连接
limit_rate 1M;
limit_conn addr 1;
# CDN 带宽封顶(云厂商控制台)
视频资源合理 TTL:
- 视频文件 (.mp4/.ts) → 7~30 天
- 封面图/缩略图 → 3~7 天
- 字幕文件 (.vtt) → 1~7 天
- HLS m3u8 索引文件 → 2~5 秒(直播场景特殊)
场景③:音画不同步
工单特征: 画面和声音对不上,且越往后延迟越严重。
根因: 转码时帧率参数错误(如源文件 24fps 被设成 30fps),导致时间戳逐帧偏移累加。
排查方法:
ffprobe -v error -show_entries stream=index,codec_type,duration -of json video.mp4
# 对比视频流和音频流的总时长是否一致
# 如果视频 5400s,音频 5398.5s
# → 视频比音频长 1.5s,到结尾时音画差 1.5 秒
修复:
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 四个排查方向
- TTL 太短:缓存时间短导致频繁回源
- cache_key 参数问题:URL 带随机参数(如 ?t=timestamp)导致每次都是 MISS
- 没做预热:新资源上线没提前推到 CDN 节点
- 大文件分片回源:超大文件无法完整缓存,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 限速/限连接
排查方法:
# 按流量大小排序,看什么 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 缓存。
# 按请求次数统计(不是按流量)
awk '{print $7}' /var/log/nginx/access.log | \
sort | uniq -c | sort -rn | head -10
动态接口能否缓存?
- 所有人返回的数据一样 → ✅ 能加 Redis / Nginx 缓存
- 每人每次返回不同(如播放 token)→ ❌ 不能缓存,改用限流/扩容
# 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 上传配置
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 保护
- 编码器不支持(罕见冷门格式)
排查:
# ① 文件大小
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 解析错误。
排查方法:
# 伪造来源 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 版本作为兼容格式。
六、常用排查命令汇总
文件检查
ffprobe -v error -show_entries stream=codec_name,width,height -of json video.mp4
file video.mp4
ls -lh video.mp4
CDN 检查
curl -I https://cdn.example.com/video.mp4 # 看 X-Cache 状态
curl -H "X-Forwarded-For: 地区IP" -I URL # 模拟地区请求
服务器负载
top # CPU
iftop -i eth0 # 实时带宽
sar -n DEV 1 3 # 网卡流量统计
日志分析
# 按请求次数排序
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
转码
ffmpeg -i input.mov -c:v libx264 -c:a aac output.mp4
七、核心排查思维
- 先保护,再排查 — 突发状况(带宽飙高)先止血,再慢慢找原因
- 先优化,再扩容 — 扩容是最后手段,不是第一选择
- 先局部,再全局 — 一个文件有问题?先看文件本身,别先怀疑整个服务
- 变更前先沟通确认 — 改参数前问清楚影不影响其他业务,跟相关方确认
八、涉及的核心概念对比
视频编码
- 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 报错 → 文件损坏或格式不对