游戏客户端断点下载:资源更新失败时,别让玩家从零开始

讨论资源更新中的分片下载、断点续传、哈希校验、临时文件和异常恢复,降低移动端更新失败率。

更新失败最消耗耐心

玩家愿意等一次更新,不一定愿意等第二次。尤其移动端资源包动辄几百 MB,下载到 90% 后失败,如果客户端让他从 0% 重新开始,体验会非常糟。很多差评不是因为游戏内容不好,而是因为更新器把玩家挡在门外。

断点下载的目标很朴素:已经可靠拿到的字节,不要重复下载;已经损坏的字节,要能发现并替换;下载过程被打断后,下次能从可信位置继续。听起来简单,真正做起来要处理临时文件、分片校验、磁盘空间、CDN 差异、网络切换和版本切换。

分片比整包更可控

整包下载最简单,但失败成本高。分片下载可以把一个资源包拆成固定大小的块,每个块有自己的哈希和大小。客户端按 Manifest 下载缺失分片,写入临时目录,全部校验通过后再合成或标记为可用。

flowchart TD
    A[读取远端 Manifest] --> B[检查本地分片状态]
    B --> C{分片完整?}
    C -->|是| D[跳过下载]
    C -->|否| E[请求分片]
    E --> F[写入临时文件]
    F --> G[分片哈希校验]
    G -->|失败| H[删除分片并重试]
    G -->|成功| I[记录分片完成]
    I --> J{全部完成?}
    J -->|否| B
    J -->|是| K[原子切换资源包]

分片大小要权衡。太小会增加请求数和索引开销,太大又会让失败重试成本变高。移动游戏里常见做法是根据资源包大小和网络环境选择 1MB 到 8MB 的分片,并限制并发数。

临时文件不能污染正式资源

下载过程中的文件一定要放在临时区,不能直接覆盖正式资源。只有所有分片校验通过、版本兼容检查通过、磁盘写入确认成功后,才能把资源包切到活动目录。否则玩家在下载中途杀进程,下次启动可能读到半个资源包。

临时区还要定期清理。旧 manifest 的残留分片、失败下载的临时文件、已过期活动资源,如果一直留着,会慢慢吃掉磁盘。清理时要小心,不要删除当前可回滚版本,也不要删除正在下载会话使用的文件。

校验要分层

只依赖 HTTP 状态码不够。CDN、代理、磁盘和代码 bug 都可能让文件内容不对。客户端至少要做分片哈希、整包哈希和 Manifest 签名校验。分片哈希帮助局部重试,整包哈希确认最终结果,Manifest 签名防止配置被篡改。

校验失败后不要无限重试同一个 CDN。可以切备用域名、降低并发、清理临时文件后重下。若多次失败,要给玩家明确提示,并保留错误码。最糟糕的是一直转圈,既不成功也不失败。

版本切换要小心

玩家下载过程中,服务端可能发布了新版本 Manifest。客户端要决定继续完成旧版本,还是切换新版本。通常更稳的策略是:如果旧版本仍被服务端接受,就完成当前下载;如果旧版本已废弃,再停止并切到新 Manifest。频繁切换会让玩家永远下不完。

这要求服务端保留一定时间的旧资源,不要一发布新版本就删除旧 CDN 文件。客户端和发布系统要约定资源保留窗口,否则断点下载设计得再好,也会因为远端文件消失而失败。

小结

断点下载是资源更新的底线能力。它不追求炫技,只要求每个字节都有状态、每个失败都有归因、每次切换都可恢复。移动网络不稳定是常态,客户端不能把这种常态变成玩家的重复劳动。

线上排查要看哪几类数据

断点下载的问题,线上看起来常常像“更新失败”。但失败原因可能完全不同:磁盘不足、CDN 超时、校验失败、用户切后台、代理劫持、分片顺序错乱、本地临时文件损坏。日志必须把这些原因区分开,否则运营只能告诉玩家重装。

比较有用的字段包括资源包 ID、manifestId、分片编号、已下载字节、目标哈希、当前网络类型、剩余磁盘空间、失败错误码、重试次数和 CDN 节点。客户端还要记录一次下载会话的 traceId,方便把多次启动、多次重试串起来。

验收时不要只测顺畅网络。要故意在下载到 10%、55%、99% 时杀进程,切后台,断网,切换 Wi-Fi 和移动网络,清理系统缓存,再启动继续下载。断点下载真正的价值不在于平时快,而在于这些粗暴场景里仍然不把玩家推回起点。

分片状态机要简单可靠

每个分片最好有明确状态:未开始、下载中、已下载待校验、校验通过、校验失败、废弃。状态不要只存在内存里,下载过程中要定期落盘。玩家杀进程后,下次启动可以读取分片状态和临时文件,重新校验已完成分片,再继续下载缺失部分。

状态落盘要小心写入顺序。先写数据,再 fsync 或确认写入,再更新索引状态。否则索引显示分片完成,但文件实际没写完。移动端文件系统和系统缓存并不总是按你想象的顺序落盘,尤其在低电量、存储空间不足或应用被系统杀掉时。

校验失败的分片不要继续复用。应该删除临时文件,记录失败原因和 CDN 信息,再重新下载。如果同一分片连续失败,可能是远端文件异常、代理污染或本地磁盘问题。此时继续无限重试没有意义,应切换 CDN 或提示玩家。

磁盘空间要提前检查

资源更新经常忽略磁盘空间。玩家剩余空间只够下载压缩包,却不够解压后的资源;或者分片下载完成了,合并时空间不足。客户端在开始前要估算峰值空间,包括临时分片、合并文件、解压目录和回滚版本。

如果空间不足,提示要具体。不要只说“更新失败”,要告诉玩家需要释放大约多少空间。对可选资源,可以允许玩家跳过;对强制资源,则要阻止下载开始,避免下载一半失败。

清理策略也要谨慎。可以清理废弃临时文件、过期活动包、旧日志和可重新下载的缓存,但不能删除当前版本资源和上一份可回滚资源。清理动作最好在更新前和更新成功后各做一次,避免临时文件长期堆积。

CDN 和 Manifest 要配合

断点下载依赖远端资源稳定。如果 Manifest 指向的文件频繁被覆盖,客户端本地分片就可能和新文件混在一起。资源文件名最好包含哈希,内容不可变;新版本发布新文件,旧文件保留一段时间。

CDN 返回也要校验。某些网络环境下,运营商代理可能返回 HTML 错误页,HTTP 状态却看起来正常。客户端不能只看 200,还要看 Content-Length、分片范围、哈希和必要的响应头。Range 请求失败时,要能降级为重新请求整个分片,而不是把错误内容写进资源。

备用 CDN 不是简单换域名。不同 CDN 的缓存刷新速度和跨区表现不同。客户端切换时要记录当前 CDN、失败码和耗时,发布系统也要能看到哪个节点异常。否则出了问题只能全量切换,影响范围更大。

下载体验也需要 UI 设计

更新界面不能只显示百分比。玩家需要知道当前在下载、校验、解压还是等待网络。校验和解压阶段没有网络流量,但耗时可能很长,如果 UI 仍然写“下载中”,玩家会以为卡住。

可恢复下载要显示恢复结果。比如“已校验 320MB,继续下载剩余 80MB”,玩家会觉得之前的等待没有浪费。失败后也要保留重试按钮和错误码,方便客服定位。对强制更新,退出路径要明确;对可选更新,不要把玩家困在更新页。

并发下载要有限制

提高并发能让下载更快,但移动端并发太高会带来副作用:弱网下超时更多,磁盘写入更碎,低端机校验更慢,甚至影响游戏主线程。下载器应该根据网络类型、设备性能和当前场景动态调整并发。Wi-Fi 空闲界面可以高一点,移动网络或战斗中要低一点。

并发调度还要公平。一个巨大资源包不能长期占满所有下载通道,让关键小文件排队。可以给资源分优先级:进入当前玩法需要的资源最高,后台预取次之,高清可选资源最低。玩家点击某个尚未下载的玩法时,相关资源应提升优先级。

校验耗时也要展示

很多更新器下载完成后停在 100%,实际在校验或解压。玩家看到 100% 不动,会认为卡死。UI 应该把阶段拆开:下载、校验、解压、安装、清理。每个阶段都可以没有精确百分比,但要有明确文案和超时处理。

校验和解压最好切片执行。一次性校验大文件会占 CPU,可能导致界面无响应。可以每处理一段让出主线程,或者放到后台线程并限制优先级。低端机上宁可多花几秒,也不要让系统判定应用卡死。

发布系统要支持回滚窗口

客户端做断点下载,发布系统也要配合保留旧文件。假设玩家下载旧版本到 80%,此时发布系统删除旧 CDN 文件,他下次继续时一定失败。更好的做法是保留至少一个资源回滚窗口,例如 7 到 14 天,覆盖大多数慢更新用户。

Manifest 也要可追溯。每个 manifestId 对应一组不可变资源,发布记录里保留创建时间、适配客户端版本、灰度范围和回滚状态。客户端日志带 manifestId 后,工程师才能知道玩家到底卡在哪个资源版本。

异常恢复要能自愈

临时文件索引损坏、本地分片缺失、哈希记录不一致,这些都可能发生。下载器启动时要先做一次轻量自检:索引里完成的分片是否存在,大小是否匹配,必要时重新校验。发现不一致时,宁可把分片退回未完成,也不要相信错误状态。

自愈能力能减少客服成本。玩家不需要知道临时文件出了问题,客户端自己清理并继续。只有连续自愈失败、磁盘不足或远端资源不可用时,才把问题交给玩家。

玩家侧的信任感

断点下载做得好,玩家未必会夸;做得差,玩家一定会记住。更新器要给玩家稳定预期:进度会保留,失败能重试,错误有原因,空间不足能提前知道。尤其在大版本更新时,这种信任感很重要。

客户端也要避免夸张承诺。预计时间可以给范围,不要显示过于精确的倒计时;网络波动时说明速度变化,不要让进度条倒退;校验失败时说明正在修复,不要直接从 100% 跳回 0%。这些细节会决定玩家是否愿意继续等。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页