Appearance
MLive 多任务下载框架
自研 MLive 下载框架,解决 UnityWebRequest 在弱网下 timeout 失效的系统性 Bug,支持多任务/断点续传/资源校验。
背景
B 站虚拟 3D 项目需要动态下发模型——用户选择模型后从服务器下载,而不是把所有模型打包到客户端。
最初基于 UnityWebRequest 实现,但上线后发现弱网/断网重连时下载会永久卡住。
问题:UnityWebRequest 的 timeout Bug
UnityWebRequest 的设置:
csharp
request.timeout = 30; // 设了 30 秒超时Bug 现象:
- 弱网环境下,下载一直等待,timeout 不生效
- 断网重连后,下载不自动重试,也不抛异常
- 用户看到"下载中"的 loading 永远转圈
根因:UnityWebRequest 的底层 libcurl 在 DNS 解析和 TCP 连接阶段不计入 timeout,导致弱网下 timeout 形同虚设。
方案
自研下载管理器
DownloadManager
├── TaskQueue ← 多任务并发控制(最大 3 个并发)
├── DownloadWorker ← 单任务下载(分片 + 断点续传)
├── RetryPolicy ← 指数退避重试
├── IntegrityChecker ← MD5 校验
└── CacheManager ← 本地缓存索引流程
1. 鉴权 → 获取 Cookie
2. 请求资源列表 → 比对本地缓存 → 确定需要下载的模型
3. 请求下载信息(地址 + MD5)→ 分片下载
4. 下载完成 → 生成 MD5 → 与服务器下发 MD5 比对 → 确认完整性
5. 更新本地缓存索引弱网处理
- Timeout 自控:不用 UnityWebRequest.timeout,用 C# 的 CancellationTokenSource 手动计时
- 断点续传:HTTP Range 请求实现
- 指数退避重试:1s → 2s → 4s → 8s → 放弃
产出
- 在 Z-star 和虚拟 3D 项目上线使用 5 个月,稳定无 Bug 反馈
- 相关专利:Unity 资源更新与管理下载方法(已提交)
- 后续扩展:断点续传(Resume)
教训
- 不要盲目信任框架 API——timeout 这种基础功能也要验证
- UnityWebRequest 的 Bug 至今未修(至少当时版本)
- 自研不是目的,绕过系统缺陷才是——如果 UnityWebRequest 没问题,不会重新造轮子
架构图说明
下载器框架图
下载器继承 IMliveDownloader 接口,暴露能力:更新官方列表、返回封面/模型文件路径、返回/验证模型资源状态、下载模型资源。
内部分三层:配置层(URL、客户端版本 ID、引擎版本 ID、客户端类型 ID、缓存目录)、缓存层(后缀缓存 + 本地响应体缓存)、下载层(返回 Task 的下载接口)。请求流程:读配置 → 查缓存 → 缓存缺失时走下载层 → 写入缓存 → 返回路径。
下载器时序图
参与方:用户 → 直播姬 → 虚拟姬 → MLive 下载器 → MLive 缓存器 → 服务器。
获取资源列表:用户登录直播姬 → cookie 传给虚拟姬 → 传给下载器 → 请求服务器 MLive 资源列表 → 服务器校验 cookie/版本/引擎信息 → 返回列表 → 下载器校验、缓存、更新 → 返回虚拟姬。
下载资源:用户加载某 ID → 虚拟姬请求下载器 → 缓存器检查 ID/版本/完整性 → 缓存有效则返回路径;无效则向服务器下载 → 服务器返回资源地址和 MD5 → 下载 → 校验完整性 → 写入缓存 → 返回本地路径。