location_on 首页 keyboard_arrow_right 旅行影像 keyboard_arrow_right 正文

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

旅行影像 access_alarms2026-01-22 visibility152 text_decrease title text_increase

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

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

引子 做视频应用,缓存管理看似简单,做不好就会遇到磁盘暴涨、播放卡顿、离线功能失灵、用户抱怨“清不了缓存”的问题。为了蘑菇视频的体验,我先后试了三套方案,逐步优化。下面把每套方案的思路、优缺点、实测数据和最后我选择的方案说清楚,方便你直接拿去参考或复用。

场景约束(先说清楚)

  • 目标设备为中高端 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 自适应(小视频小片段,长视频大片段)。
  • 写入流程(伪代码):
  1. 计算 contentHash;如果存在返回路径。
  2. 创建 tempFile,边下载边写,记录已下载长度。
  3. 下载完成后校验 hash -> atomic rename 到 finalPath。
  4. 更新索引(事务):path, size, resolution, lastaccess, accesscount++。
  • GC 选择(伪代码):
  • 按 score 升序取候选,跳过正在播放且被 pin 的项,直到总大小 ≤ low_watermark。

用户操作与体验设计

  • 给用户“缓存大小”滑动条(128MB/512MB/2GB/无限),并有“一键清理缓存”和“仅保留已下载的视频”选项。
  • 清理提示采用渐进式(建议先清理临时区,再长期区),避免误删正在下载或播放的内容。
  • 在设置页面显示缓存占用详情(按视频、分辨率分类),便于高阶用户管理。

常见坑 & 防护

  • 索引和文件不同步:崩溃后执行一次完整扫描修复(scan-once),把孤立文件或索引缺失的项修正。
  • 网络变化导致临时文件膨胀:对临时文件设置超时,不活跃的半成品在 N 分钟后自动删掉。
  • DRM 内容:DRM 视频应走不同路径,不能去重到通用缓存,严格隔离并遵守授权。

report_problem 举报
91网0最让人服气的,不是反转,预算被砍后,团队用一种“笨办法”顶住了
« 上一篇 2026-01-22
新91视频的后劲来自哪里?:某位主演临时加戏,反而把人物救活了,这才是它最聪明的地方
下一篇 » 2026-01-22