UE5.7 DDC 配置实践:Zen Server 部署指南
“改了一个材质的 Roughness 参数,Cook 跑了 45 分钟。”
这是上个月在朋友工作室亲眼看到的——一个 12 人的独立团队,每次改点东西就要等大半个小时 Cook。检查之后发现:DDC 根本没配。所有资产,每次 Cook,全部重新算一遍。
他们花的钱买 build 机器,不如把 DDC 配好。
DDC 到底是什么?
DDC(Derived Data Cache,派生数据缓存)是 UE5 对”已经算过的东西不再算第二遍”的实现。当你 Cook 一张贴图、编译一个 Shader、或者导入一个 Mesh 时,引擎会把处理后的结果缓存在 DDC 里。下次用到同样的输入,直接从缓存读,跳过计算。
DDC 的缓存键(Cache Key)由这些因素决定:
1 | DDC Key = Hash(Asset 源码) + Engine 版本 + 平台 + 编译配置 + DDC 版本号 |
任何一个变了,Key 就不同,等于 Cache Miss,要重算。所以:
- 升级引擎 → 全量 DDC Miss
- 改了资产 → 只 Miss 这一个
- 换了平台(Win64 → Linux) → 全量 Miss
- 改了 Shader 模板 → 所有用到它的材质 Miss
UE 5.7 的 DDC 格局:Zen 一统天下
UE5 的 DDC 后端经历了几轮变迁:
1 | UE 4.x UE 5.0~5.3 UE 5.4~5.6 UE 5.7 |
到了 UE 5.7,Zen Server 已经是事实标准。Epic 把优化精力全部放在 Zen 上,Shared DDC(NAS 共享目录)虽然还能用,但官方文档的第一推荐就是 Zen。
为什么 Zen 比其他方案好?
| Shared DDC (NAS) | Cloud DDC (S3) | Zen Server | |
|---|---|---|---|
| 延迟 | 低(局域网内) | 高(HTTP 往返) | 极低(gRPC 流式) |
| 并发 | SMB 锁竞争 | 好 | 优秀(无锁设计) |
| 去重 | 无 | 按 blob | 内容寻址,自动去重 |
| 运维 | 简单 | 需要云服务 | 一个二进制,一行命令启动 |
| UE 5.7 推荐度 | 兼容方案 | 已弃用 | ⭐⭐⭐⭐⭐ |
Zen Server:十分钟搭起来
UE 5.7 自带 Zen Server 的二进制和 Docker 镜像。最简单的部署:
方案一:裸机启动
1 | # 从 UE 5.7 引擎目录找到 ZenServer.exe |
方案二:Docker Compose(推荐 CI 环境)
1 | # docker-compose.yml |
启动后验证:
1 | # gRPC 健康检查 |
DDC Graph:缓存分层策略
UE 5.7 的 DDC Graph 在 DefaultEngine.ini 中配置。最佳实践是三层缓存:
1 | ; Engine/Config/DefaultEngine.ini |
三层配合的效果:
1 | 查询路径(读): |
冷启动问题:最容易被忽略的成本
DDC 最大的坑不是配置,是冷启动。
场景:团队新来一个成员,git clone 项目,打开 Editor,点了 Play。
此时他的 Local Zen 是空的。所有 Shader 编译、所有资产加载,全部需要重新计算。Editor 启动 30 分钟是常事。
解决方案:种子 DDC
UE 5.7 提供了 UnrealZen 工具来做 DDC 预热:
1 | # 在 CI 构建机(已有热 DDC)上,导出种子包 |
CI 流水线里的种子策略:
1 | 每周一凌晨 CI 触发: |
CI 环境的 DDC 最佳实践
反模式:每个 CI Agent 跑自己的 Local DDC
1 | ❌ Agent #1 ── Local DDC ──┐ |
正确做法:所有 Agent 指向同一个 Shared Zen
1 | ✅ Agent #1 ──┐ |
CI 环境下的额外配置:
1 | ; CI Agent 的 DefaultEngine.ini 覆盖 |
Cook 时指定 DDC 参数:
1 | # CI Cook 命令 — 利用 Shared Zen 加速 |
监控与调试:DDC 不是黑盒
UE 5.7 提供了丰富的 DDC 可观测性工具。
运行时统计:
1 | # 启动 Editor 时记录 DDC 统计 |
Zen Server 自身监控:
Zen Server 暴露 Prometheus 端点:
1 | # Prometheus scrape config |
关键指标:
| 指标 | 含义 | 告警阈值 |
|---|---|---|
zen_cache_hit_rate |
缓存命中率 | < 80% |
zen_cache_size_bytes |
缓存占用 | > 磁盘 80% |
zen_request_latency_p99 |
P99 延迟 | > 10ms |
zen_cold_storage_fallback_rate |
回退到本地冷存储的比例 | > 5% 说明热数据被淘汰 |
常见问题诊断:
1 | # 1. 命中率低:检查 key 是否频繁变化 |
五个常见错误
错误一:Zen Server 放云上
“我们把 Zen Server 部署在阿里云上,整个团队 VPN 连过去。”
结果:gRPC 延迟 30ms+,每次 DDC 查询比本地计算还慢。而且项目资产通过公网传输,安全风险不可控。Zen 必须部署在本地机房,和 Editor/CI Agent 在同一局域网内,延迟 < 2ms。所有数据不出机房。
错误二:不设 Local Zen 上限
本地磁盘 1TB,Zen 用掉了 900GB——都是三个月前的资产,早就不用了。MaxSizeGB 是强制性的,不是可选的。
错误三:不同分支共用同一个 Namespace
main 分支和 feature-x 分支如果共用同一个 Zen namespace,DDC 会互相污染。正确做法:
1 | ; 每个分支独立的 DDC namespace |
错误四:CI 和开发者共用同一个 Local Zen
CI Agent 的 Local Zen 会写入大量临时数据,和开发者共用会挤掉有效缓存。CI Agent 应该用独立的 Zen 实例,或者直接只用 Shared Zen。
错误五:忽视 DDC 版本号
引擎升级后,旧的 DDC 数据不会被自动清理——它会一直占着磁盘空间,但再也不会被命中。升级引擎后清理旧的 Local Zen 数据:
1 | # 引擎升级后清理旧 DDC |
更新记录
- 2026-06-05:初稿发布。
一个 12 核的 CPU 跑 Cook 任务,80% 的时间在等 IO。你把 CPU 换成 32 核,等待时间还是 80%——只不过多了 20 个空闲的核而已。DDC 要解决的不是”算得快”,而是”不用算”。你的 DDC 命中率是多少?