目录
一、背景
二、现象定位
三、问题探究
四、分析原因
五、总结
一、背景
一个春暖花开的午后,发生了一个诡异的现象:
IT同学:哪个域名流量这么大,太占用公司办公网资源了!
某业务:想问下这个问题需要怎么解决呢,我们已经遇到好几例了,上次有个店员一天消耗了60G,这个店员130G 。
我:收到CDN带宽告警,哪个cdn域名用了这么多带宽啊!
二、现象定位
1、问题流量定位
通过CDN流量分析,定位到top流量消耗都是几个MP4视频。 点击流量最高的视频链接分析了下,是一个大小1G,视频时长约30分钟的MP4视频。
于是找业务同学确认:
我:这个视频是做什么用的啊?
业务同学:这是一个学习培训视频,推送给了2500人学习观看。
我:嗯?不对啊,CDN监控显示花费流量120TB,如果2500人完播看完一个视频,正常应该是 2500x1g =2.5TB,这多出的50倍流量怎么来的?
2、流量使用验证
我通过谷歌浏览器访问了业务上传的另一个视频(视频大小500M时长40分钟),观看视频并开启F12分析下流量使用。


完播居然花了8G,发送了3700个206请求!!!!
现象:
开始播放后,会出现3个206请求;第三个请求发完后,浏览器随时间发起多个206请求;请求来来回回Range。我:这不行啊,我赶紧ai、百度、google各种搜索。
发现通过命令ffmpeg处理视频可以解决这个问题:
ffmpeg -i bad.mp4 -c copy -movflags faststart good.mp4将新视频上传,f12分析视频;206请求只有一个了;且多206请求现象消失;完播视频流量消耗=原视频大小。ffmpeg能解决该问题,但长视频还是将其转为流媒体格式,推动业务改进后流量监控如下图:

三、问题探究
四个问题:
为什么一开始会出现3个206请求?3个206请求后,为什么会发起多个206请求?为什么请求头Range会来回跳跃?为什么使用ffmpeg处理视频后能解决这个问题?要分析该奇异现象发生原因就得知道整个播放流程是怎么运作的。
1、MP4 文件结构
MP4 文件由多个 Box(盒子)组成,主要包括:
MP4 文件结构:┌─────────────────────────────────────┐
│ ftyp (文件类型) │ ← 文件开头
├─────────────────────────────────────┤
│ mdat
─────────────────────────────────────┤
│ moov (元数据) │ ← 可能在开头或结尾
│ ├─ mvhd (文件头信息) │
│ ├─ trak (视频轨道) │
│ │ ├─ stco (Chunk偏移表) │ ← 记录数据位置
│ │ ├─ stsz (样本大小表) │ ← 记录每帧大小
│ │ └─ stsc (样本到Chunk映射) │ ← 记录帧的分布
│ └─ trak (音频轨道) │
│ ├─ stco (Chunk偏移表) │
│ ├─ stsz (样本大小表) │
│ └─ stsc (样本到Chunk映射) │
└─────────────────────────────────────┘
关键点:
moov box 包含了所有的索引信息(类似目录);mdat box 包含了实际的音视频数据;播放器必须先读取 moov 才能知道数据在哪里。2、浏览器播放流程

从Media信息得知Chrome 浏览器使用 FFmpegDemuxer 来解析读取 MP4 文件,参考谷歌浏览器源码,播放流程如下:

3、源码分析
mov_find_next_sample(这一个函数返回的是下一个样本位置):
static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st){
..........
..........
// 遍历所有流,找到最佳样本
for (i = 0; i < s->nb_streams; i++) {
AVIndexEntry *current_sample = &index_entries[current_index];
int64_t dts = current_sample->timestamp;
//
if (dtsdiff <= AV_TIME_BASE && current_sample->pos < sample->pos) {
// DTS 差 ≤ 1 秒,选择位置靠前的(减少 seek)
sample = current_sample;
} elseif (dtsdiff > AV_TIME_BASE && dts < best_dts) {
// DTS 差 > 1 秒,选择 DTS 最小的(保证顺序)
sample = current_sample;
..........
..........
}
}
return sample;
}
}
在mov_find_next_sample函数中还有一个开关interleaved_read:
在解复用器层对多个轨道的包进行交错。对于交错不良的文件,这可以防止由于不同轨道之间包的大间隙而引起的播放问题,因为MOV/MP4文件对包的放置没有要求。然而,对于非常交错不良的文件,这可能会导致过多的寻道操作,因为需要在轨道之间寻道,所以禁用此功能可能会防止I/O问题,但代价是可能影响播放。
理想情况下,一个交错良好的 MP4 文件 会将音频和视频数据包按照时间顺序交替排列:
[视频包1] [音频包1] [视频包2] [音频包2] [视频包3] [音频包3] ...这种交错存储方式的主要优点包括:
减少磁盘访问次数:播放器能连续读取音视频数据,提高读取效率;降低播放缓冲区需求:播放时能够平滑加载音视频数据;支持渐进式下载和播放:支持按需下载,提升流媒体性能。然而,如果音视频数据没有交错,而是集中存储,比如:
[视频包1] [视频包2] [视频包3] ... [音频包1] [音频包2] [音频包3] ...会带来以下问题:
频繁寻址:播放器需要在视频和音频数据之间跳转,增加磁盘访问次数;大量 HTTP Range 请求:每次跳转都需要发起新的 HTTP 请求,降低性能;播放不稳定:频繁请求数据会导致卡顿和延迟,影响用户体验。4、测试验证
由于谷歌浏览器使用的是 FFmpegDemuxer 解码并读取视频信息,其底层依赖于 FFmpeg 代码实现,只是在上层进行了浏览器的缓冲/预读封装。
测试视频:longbad.mp4(该视频存在较差的音视频交错问题)
测试工具:FFmpeg(模拟谷歌浏览器的解码处理过程)
本次测试旨在评估 interleaved_read 参数对视频播放的影响,并借助ffmpeg工具分析视频多206的问题。
交错读取(Interleaved Read):默认情况下,FFmpeg 会将音视频数据交错存储,Interleaved为1;ffmpeg -i https://xxxx/longbad.mp4 -ss 60 -t 5.0 -y output.mp4 -loglevel trace 2>&1 | grep "Range"
-i https://...:从远程服务器读取输入文件
-ss 60:从视频的第60秒开始
-t 5.0:截取5秒的片段
-y:覆盖输出文件
output.mp4:输出文件名
通过wc -l统计发现请求了5078次!,看5s的视频请求了5078次。
结合cdn日志和longbad视频的音视频轨道分析:
Range来回跳动,在60s时刻从5967030跳到46622680相同时间范围,音频offset和视频offset距离很远非交错读取(Non-interleaved Read):通过设置 -interleaved_read 0,FFmpeg 会将音频和视频数据分开读取。ffmpeg -interleaved_read 0 -i https://xxxx/longbad.mp4 -ss 60 -t 5.0 -y output.mp4 -loglevel trace 2>&1 | grep "Range"
通过wc -l统计发现请求了3只请求了三次
四、分析原因
1、为什么一开始会出现3个206请求?
原因:moov box 在文件末尾。
moov存着视频的索引信息,详细看MP4 文件结构。
正常的 MP4 文件播放流程:
读取 ftyp+moov → 在头部直接读mdat ----一个206但问题视频的 moov 在文件末尾:

导致:
1. 读取 ftyp和moov → 不在头部啊去尾部查 -----第一个2062. 读取尾部moov → -----第二个206
3. 开始播放视频 → -----第三个206
2、为什么会发起多个206请求,且Range范围来回跳动?
原因:视频文件交错不良 + FFmpeg 的读取策略。
1)交错不良的文件布局
通过获取视频文件offset的信息制作了一个图:
音视频物理位置交错图情况:X轴 = Packet在文件中的物理顺序(按pos(offset)排序后的索引)
Y轴 = Stream类型(0=视频,1=音频)
每个条形 = 一个packet
颜色 = 红色=视频packet,青色=音频packet
可以看到有一大片音频在前边
[音频包1] [音频包2] [音频包3] ... ... [视频包1] [视频包2] [视频包3]2)FFmpeg 的读取策略导致来回跳跃
mov_find_next_sample() 的选择逻辑:
时间差 ≤ 1 秒时,优先选择位置靠前的帧;但交错不良导致"位置靠前"的帧距离offset很远。举例音视频两个offset
A1 下一个V0
选择策略
时间轴(微秒):
0 10000 20000 30000 40000
├─────────┼──────────┼──────────┼──────────┤
│ │ │
│ A1 V0
│ (23219) (33333)
│ │ │
│ └──10114──┘
│ (差值 < 1秒)
│
A0 (0)
V0 (0)
当视频帧之间时间<1秒 会选择最小的offset( pos )
这就导致交错不良的文件,DTS 差小但文件位置差大,然后来回请求
3、为什么使用ffmpeg处理视频后能解决这个问题?
原因:fmpeg对视频处理后,会对音视频的位置进行重新编排(流媒体除外),底层默认处理。
处理视频文件后的音视频交错图:
ffmpeg -i bad.mp4 -c copy -movflags faststart good.mp4-i 输入指定文件
-c -copy 流拷贝
- movflags faststart 将视频moov提提前
ffmpeg会对其物理位置进行重新编排!!!
av_interleaved_write_frame() (libavformat/mux.c)
↓
ff_interleave_packet_per_dts() (libavformat/mux.c)
↓
static int interleave_compare_dts(AVFormatContext *s,
const AVPacket *next,
const AVPacket *pkt)
{
AVStream *st = s->streams[pkt->stream_index];
AVStream *st2 = s->streams[next->stream_index];
// 1. 比较 DTS(转换到统一时间基)
int comp = av_compare_ts(next->dts, st2->time_base,
pkt->dts, st->time_base);
// 2. 处理音频预加载(audio_preload)
if (s->audio_preload) {
int preload = st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
int preload2 = st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
if (preload != preload2) {
// 音频包提前一点时间
int64_t ts = av_rescale_q(pkt->dts, st->time_base, AV_TIME_BASE_Q)
- preload * s->audio_preload;
int64_t ts2 = av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q)
- preload2 * s->audio_preload;
comp = (ts2 > ts) - (ts2 < ts);
}
}
// 3. DTS 相同时,按流索引排序
if (comp == 0)
return pkt->stream_index < next->stream_index;
return comp > 0;
}
五、总结
流媒体格式(如HLS)在带宽使用和播放流畅度上更优,但改造成本高。MP4格式因兼容性强和成本较低,仍是主流选择。综合考虑使用场景和成本,我们选择:
短视频统一使用 FFmpeg 处理,确保 moov box 在文件开头,优化音视频交错,避免频繁的 Range 请求。长视频采用 HLS 等流媒体格式,按需加载视频片段,提升播放流畅度和带宽利用率。>>>>
参考资料
The investigation of excessive FFmpeg requests: https://blog.dreamfever.me/posts/2024-06-09-poor-performance-of-ffmpeg-i-url/#referenceendless canceled http requests when playing an mp4 in a <video> tag: https://issues.chromium.org/issues/40292515ChromiumSrouce: https://source.chromium.org/chromium/chromium/src/+/main:third_party/ffmpeg/libavformat/mov.c;l=11048;bpv=1;bpt=1FFmpegSoure: https://github.com/FFmpeg/FFmpeg/blob/94f2274a8b61438572f0873ccf430e55ce0e0e2b/libavformat/mov.c#L9767-L9795作者介绍
邹泉安,转转运维部。
来源丨公众号:转转技术(ID:zhuanzhuantech)
dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn
活动推荐
5月22日,2026 XCOPS 智能运维管理人年会「广州站」重磅来袭!聚焦大模型迭代、AI Agent 深度应用等技术热点,邀请一众行业领军人物、技术大咖,从技术架构、实战案例到科研成果,与大家一起探索AI应用于智能运维与数据库的最佳方式,共同破解垂类智能体落地、多Agent协同、数据库自治技术工程化、核心系统信创与智能化平衡等现实难题。
点击链接即可报名: