一条命令让CDN视频带宽成本降低90%!!!

邹泉安 2026-05-10 09:56:00
目录

一、背景

二、现象定位

三、问题探究

四、分析原因

五、总结

 

一、背景

 

一个春暖花开的午后,发生了一个诡异的现象:

 

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    →                     -----第二个2063. 开始播放视频    →                      -----第三个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很远。

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
举例音视频两个offsetA1 下一个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/#reference

  • endless canceled http requests when playing an mp4 in a <video> tag: https://issues.chromium.org/issues/40292515

  • ChromiumSrouce: https://source.chromium.org/chromium/chromium/src/+/main:third_party/ffmpeg/libavformat/mov.c;l=11048;bpv=1;bpt=1

  • FFmpegSoure: 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协同、数据库自治技术工程化、核心系统信创与智能化平衡等现实难题。扫描下方二维码可了解大会详情及报名↓
 
最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告