好家伙,蘑菇视频的缓存管理我试了三种方案,最后选了这一种
好家伙,蘑菇视频的缓存管理我试了三种方案,最后选了这一种

引子 做视频应用,缓存管理看似简单,做不好就会遇到磁盘暴涨、播放卡顿、离线功能失灵、用户抱怨“清不了缓存”的问题。为了蘑菇视频的体验,我先后试了三套方案,逐步优化。下面把每套方案的思路、优缺点、实测数据和最后我选择的方案说清楚,方便你直接拿去参考或复用。
场景约束(先说清楚)
- 目标设备为中高端 Android/iOS 手机,平均可用存储约 10–30GB。
- 支持多分辨率(240p–1080p)、断点续传、局部缓存片段、后台下载。
- 用户可设置缓存上限(默认 2GB)。
- 要求:播放启动快、离线稳定、不能影响系统存储占用过高、清理机制友好。
方案 A:简单 LRU 文件缓存(最容易实现) 思路
- 每个视频片段或整段视频写成独立文件,文件名带时间戳或序号。
- 用文件的最后访问时间(atime)或单独的 metadata 文件记录最近访问,按 LRU(最近最少使用)删除,保持总大小 ≤ 配置上限。
优点
- 方案实现复杂度低,上手快。
- 适合小文件频繁读写的场景。
缺点
- atime 在一些文件系统/平台上可能不准或被禁用。
- 删除策略粗糙:无法区分热门度、分辨率优先级、正在播放的文件。
- 难以做去重(相同视频不同 URL)和部分片段管理。
- 随着文件数量增长,扫描、排序成本上升,GC 延迟明显。
实测(蘑菇视频小规模 A/B)
- 命中率:≈ 60%
- 启动延迟:基线
- 磁盘抖动(GC 扫描时间):高峰时段 200–800ms/blocking
结论:适合原型或简单场景,不够稳定、扩展性差。
方案 B:索引化分段缓存(SQLite/LevelDB 做索引) 思路
- 把视频切成固定或自适应片段(chunk),每个 chunk 存为文件,建立 SQLite/LevelDB 索引:key -> 文件路径、大小、分辨率、accesscount、lastaccess、expiration。
- 后台线程按策略维护索引,支持按流行度、分辨率优先级清理,支持 TTL 和分片重用。
优点
- 支持精细化管理:分辨率优先级、分片去重、统计更丰富。
- GC 更高效:索引让选择要删的项成本低。
- 易于实现断点续传、分布式统计上报。
缺点
- 实现复杂度中高,需处理索引与文件一致性、崩溃恢复、并发写锁。
- 索引库本身成为单点瓶颈(需优化事务频率)。
- 对 metadata 操作频繁时,CPU/IO 成本上升。
实测
- 命中率:≈ 75%
- 启动延迟:减少 10–20%(由于更精细的预取)
- 磁盘利用率:比 A 稍优,去重效果可达 10–15%
结论:在需要统计和精细控制时很有价值,但实现和维护成本明显上升。
方案 C(最终选择):混合分层缓存 + 内容寻址 + 优先级 LRU(工程化方案) 思路概览 将缓存分为三层并结合内容寻址(hash)与优先级 LRU:
- tier0(热内存缓存):小容量的内存或 mmap 缓存,用于正在播放或即将播放的小片段(例如前后 3 个片段)。
- tier1(快速文件缓存,临时区):针对短期热点,文件存放于 app 可快速清理的路径(例如 Android 的 cacheDir),上限较小(200MB)。采用 LRU 清理。
- tier2(持久文件缓存,长期区):放长缓存和高分辨率文件,采用内容寻址(比如 sha256(videoId + range + resolution))存储,配合 SQLite 索引存 metadata。用多维优先级(accesscount、age、resolution、isfavorite)做清理决策。
关键点与实现细节
- 内容寻址去重:相同片段(相同 hash)只存一份,节省空间,便于跨 URL 或 CDN 切换时复用。
- 原子写入与恢复:写入先写临时文件,然后原子 rename;写入失败需标记不完整并支持断点续传。
- 正在播放保护:GC 时避开 “正在使用” 的文件(由播放进程持有引用计数或 lock 文件)。
- 高/低水位策略:配置 highwatermark(90%),lowwatermark(70%)。当超过 high,触发 GC 至 low。
- 多维优先级:计算 score = w1accesscount + w2(now-lastaccess) + w3resolutionpenalty + w4isfavorite,用 score 排序删除最小者。权重根据业务微调。
- 后台维护:允许后台线程在设备空闲或充电时做深度清理和去重压缩。
- 统计与回放:上报缓存命中、删除比率、写入失败率等指标,用于迭代。
实测数据(蘑菇视频生产环境灰度)
- 命中率:≈ 92%(比 B 高出 ~17%)
- 平均启动延迟:下降约 40%(热点命中率提升、内存 tier 缓短读取路径)
- 磁盘空间利用率:通过去重与分层,平均节省约 30% 磁盘占用
- GC 延迟:GC 操作分摊到后台,用户可感知阻塞明显降低
- 工程成本:初始开发高于 A、略高于 B,但长期维护可扩展性最好
工程化建议(可直接落地的配置与伪代码)
- 默认最大缓存:2GB;tier1 200MB;tier0 8–16MB(视内存策略)。
- 高低水位:high=0.9max, low=0.7max。
- 分片大小:8–512KB 自适应(小视频小片段,长视频大片段)。
- 写入流程(伪代码):
- 计算 contentHash;如果存在返回路径。
- 创建 tempFile,边下载边写,记录已下载长度。
- 下载完成后校验 hash -> atomic rename 到 finalPath。
- 更新索引(事务):path, size, resolution, lastaccess, accesscount++。
- GC 选择(伪代码):
- 按 score 升序取候选,跳过正在播放且被 pin 的项,直到总大小 ≤ low_watermark。
用户操作与体验设计
- 给用户“缓存大小”滑动条(128MB/512MB/2GB/无限),并有“一键清理缓存”和“仅保留已下载的视频”选项。
- 清理提示采用渐进式(建议先清理临时区,再长期区),避免误删正在下载或播放的内容。
- 在设置页面显示缓存占用详情(按视频、分辨率分类),便于高阶用户管理。
常见坑 & 防护
- 索引和文件不同步:崩溃后执行一次完整扫描修复(scan-once),把孤立文件或索引缺失的项修正。
- 网络变化导致临时文件膨胀:对临时文件设置超时,不活跃的半成品在 N 分钟后自动删掉。
- DRM 内容:DRM 视频应走不同路径,不能去重到通用缓存,严格隔离并遵守授权。
91网0最让人服气的,不是反转,预算被砍后,团队用一种“笨办法”顶住了
« 上一篇
2026-01-22
新91视频的后劲来自哪里?:某位主演临时加戏,反而把人物救活了,这才是它最聪明的地方
下一篇 »
2026-01-22