DDC(派生数据缓存)
DDC(派生数据缓存)
这篇笔记记录我在 UE5.4 上折腾 DDC 的过程,重点是 UE5.4 默认启用的 Local Zen,以及怎么把 ZenServer 部署成团队共享的 Shared DDC。官方文档见 Using Derived Data Cache。
什么是 DDC
DDC 是 Derived Data Cache(派生数据缓存)的缩写。
很多 UE 资产在能被使用之前需要额外的"派生数据"。最直接的例子是材质:一个带 shader 的材质,在渲染之前,shader 必须针对编辑器运行的目标平台编译出来。这类派生数据体积大、而且偶尔需要重新生成,所以它不会进版本控制,而是放在 DDC 里。
Read / Write 的逻辑很简单:
- Read:如果在 DDC 里找到了派生数据,直接从存储加载到内存,这比重新处理原始资产快得多。
- Write:如果没找到,引擎从源资产重新生成派生数据,写入每一个可写节点,然后用新生成的数据。
DDC 的配置放在 BaseEngine.ini(默认值)和项目的 DefaultEngine.ini(覆盖值)里的 [DerivedDataBackendGraph] 段。这个 Graph 把缓存配成一个层级(Hierarchy):Read 按顺序访问节点直到命中,Write 会写到每一个可写节点。
DDC 的演进
| 版本 | Local DDC 形态 | 默认存储位置 |
|---|---|---|
| UE5.3 及更早 | 文件系统 DDC(松散文件) | Engine/DerivedDataCache/ |
| UE5.4 起 | Unreal Zen Store DDC | C:\ProgramData\Epic\Zen\Data\(实际在用户目录下,见下文) |
UE5.3 及更早默认用文件系统类型的 DDC 表示项目的派生数据,每个项目有自己的 DDC 文件夹,除非你专门配了一个共享的本地文件夹。
UE5.4 默认改用 Unreal Zen Store DDC 作为 Local DDC。旧的文件系统 Local DDC 被设成仅删除(delete-only)模式,并配置为 8 天清理期后删除数据。Zen 避开了用本地文件系统做 DDC 的性能瓶颈,而且所有流(stream)和项目共享一个存储,同一个资产只生成一次。
Local Zen(UE5.4 默认)
Unreal Zen Storage,也叫 ZenServer,是 Epic 做的一个程序,管理 UE 编辑器之外的多种数据,这里我们用它管理 Local DDC。它会随编辑器自动开关,也可以配置成编辑器关掉之后仍然常驻。
Zen Store Client 的特点:
- 可读写。
- 适合本地磁盘和局域网。
- 数据存在本地机器或私有局域网托管的 Zen Store 服务器上,由服务器处理磁盘持久化。这是一个无身份验证的服务,只应限定在本地连接或可信网络/VPN 内使用。编辑器通过 HTTP 向服务器发异步请求,服务器负责未用数据的清理和垃圾回收。
ZenServer 可执行文件在执行前会被复制到安装位置(Windows 上是 C:\ProgramData\Epic\Zen\Install\)。当有新版 ZenServer 同步进工作空间时,编辑器会自动检测并在启动前把新 exe 复制过去。ZenServer 设计成向后兼容,所以如果你有多个工作空间、装着不同版本的 ZenServer,编辑器只会用其中最新的那个。
CLI 工具方面:
zenserver.exe(Engine/Binaries/Win64/zenserver.exe)是服务本体,独立可执行,复制到机器上带参数跑起来就行。zen.exe(Engine/Binaries/Win64/zen.exe)是配套的命令行工具,可以在构建机脚本里指挥这组节点。
DDC 路径
官方默认路径写的是 C:\ProgramData\Epic\Zen\Data\,但实测下来 Local Zen 的数据实际落在用户目录:
C:\Users\<user>\AppData\Local\UnrealEngine\Common\Zen\Data
具体缓存数据在 ...\Common\Zen\Data\cache\ns_ue.ddc\ 下,里面是 bulkdatalist、legacyniagarasm、materialshadermap 等 bucket,文件是 .ucas 这类 UE5 新数据格式(结构上和 UE5.3 在 Engine\DerivedDataCache\Buckets 生成的缓存类似)。
而传统 Local(文件系统类型)路径 Engine\DerivedDataCache\ 下还会留一些 TestData(.dat),是遗留或测试数据。
对照一下 UE5.3:那时 Engine\DerivedDataCache\ 下有 Buckets/Content/TestData,文件是 .udd/.dat;Shared DDC 是自定义路径,文件是 .udd。
修改 Local Zen 路径和 Namespace
改路径最简单的办法是设环境变量(不用动 ini):在"编辑系统环境变量"里新建用户变量或系统变量 UE-LocalDataCachePath,值填新路径(比如 D:\UnrealDDC),重启编辑器,ZenServer 会检测到该变量并在新位置创建 Zen 子文件夹。
也可以改 ini 里的 DataPath:修改 Engine\Config\BaseEngine.ini 或 Games\Config\DefaultEngine.ini 里的 DataPath。这只对 ZenLocal 生效。实测改了之后,原来的 C:\Users\<user>\AppData\Local\UnrealEngine\Common\Zen\Data 被删除,重新生成在了 D:\Zen\Data。
Namespace 用来隔离多项目缓存。默认情况下多个项目的缓存都写进同一个 ...\Common\Zen\Data\cache\ns_ue.ddc。想隔离的话:
- 改
Engine\Config\BaseEngine.ini; - 或者改
Games\Config\DefaultEngine.ini,加上:
[StorageServers]
Local=(Namespace="project_name.ddc")
多项目共享一个 Local 存储
Zen 的卖点之一就是所有流和项目共享一个存储,同一资产只生成一次。默认多个项目的缓存全写进 ...\Common\Zen\Data\cache\ns_ue.ddc,天然共享;需要隔离才用上面的 Namespace。
禁用 ZenServer
两种办法。
办法一,改 Engine\Config\BaseEngine.ini:
; AutoLaunch 设为 false
[Zen]
AutoLaunch=false
; 删掉 DeleteOnly=true
[DerivedDataBackendGraph]
Local=(Type=FileSystem, UnusedFileAge=8, Path=%ENGINEDIR%DerivedDataCache, ...
办法二,通过 cook 命令行参数:
-ddc=NoZenLocalFallback:无论开发环境还是已安装环境,ZenLocal 都不作为后备。ZenLocal 不可用时也不会切到其他本地缓存。-ddc=InstalledNoZenLocalFallback:仅在已安装环境(只有打包后的二进制和资源)禁用 ZenLocal 后备,开发环境里 ZenLocal 仍可用作后备。
这两个参数在出版本过程中都会禁掉 ZenLocal。禁掉之后,DDC 数据会和 UE5.3 一样写回 Engine\DerivedDataCache\。
补充一句报错排查:如果遇到"准备情况检查失败。在响应性改善之前,它将被停用"这类提示,官方建议就是用上面的 -ddc=NoZenLocalFallback / -ddc=InstalledNoZenLocalFallback 禁用这个缓存存储。
Shared DDC
Shared DDC 是团队共用的缓存。别人 cook 过的东西你不必再本地生成一遍,对远程办公和构建农场尤其有用。UE5.4 有两种做法:传统的文件系统共享盘,以及把 ZenServer 部署成共享实例。
方式一:传统文件系统共享盘(BaseEngine.ini 方式)
这是一直以来的老办法,UE5.4 的 Shared DDC 仍然沿用这套文件夹形式,设置方式和以前一样。
步骤:
- 建一个共享路径,确保团队有读写权限、空间足够(2T 或更多)。
- 在项目的
DefaultEngine.ini(Engine\Project\Config\DefaultEngine.ini)里加一条覆盖:
[DerivedDataBackendGraph]
Shared=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, DeleteUnused=true, UnusedFileAge=10, FoldersToClean=10, MaxFileChecksPerSec=1, ConsiderSlowAt=70, PromptIfMissing=false, Path=\\<ddc-server>\DDC, EnvPathOverride=UE-SharedDataCachePath, EditorOverrideSetting=SharedDerivedDataCache)
- 设环境变量
UE-SharedDataCachePath(Mac/Linux 上是UE_SharedDataCachePath)指向要用的文件夹。 - 在编辑器里设置
SharedDerivedDataCache变量。
UE5.4 下也可以只改 Games\Config\DefaultEngine.ini 的 [StorageServers]:
[StorageServers]
Shared=(Type=FileSystem, UnusedFileAge=10, FoldersToClean=10, ConsiderSlowAt=70, Path=..., EnvPathOverride=UE-SharedDataCachePath, EditorOverrideSetting=SharedDerivedDataCache, CommandLineOverride=SharedDataCachePath)
[DerivedDataBackendGraph] 各字段的含义(来自 BaseEngine.ini 注释):
MinimumDaysToKeepFile:文件至少保留的天数。Root=(Type=KeyLength, ...):根节点,用 KeyLength 对长字符串做哈希后传给 AsyncPut。AsyncPut:异步写入节点,再传给 Hierarchy。Hierarchy=(Type=Hierarchical, Inner=Boot, Inner=Pak, Inner=EnginePak, Inner=Local, Inner=Shared):层级节点,按顺序读到命中为止,写则写入所有可写节点。Boot:512MB 的引导缓存,加速启动。Local:文件系统节点,关键参数有ReadOnly(能否写)、Clean(启动时清理旧文件)、Flush(清空 DDC 重来)、PurgeTransient(不保留临时数据)、DeleteUnused(后台清旧文件)、UnusedFileAge(多久未用后删除)、FoldersToClean(一次会话最多清几个文件夹,-1 为无限)、MaxFileChecksPerSec(每秒检查多少文件)、Path、EnvPathOverride、CommandLineOverride、EditorOverrideSetting。Shared/AltShared:本地之后访问的共享 DDC,参数同上。Pak/EnginePak:预生成的 DDC 数据文件(.ddp),可分发以减少运行时的拉取/生成,分别对应项目和引擎。
多套 DDC 配置切换
可以在 DefaultEngine.ini 里准备多套命名的 DDC 配置,启动时用 -ddc= 指定。下面是一个例子:S3DDC(AWS S3 桶,为远程办公设计)和 NoS3DDC(内网共享盘):
[S3DDC]
MinimumDaysToKeepFile=7
Root=(Type=KeyLength, Length=120, Inner=AsyncPut)
AsyncPut=(Type=AsyncPut, Inner=Hierarchy)
Hierarchy=(Type=Hierarchical, Inner=Boot, Inner=Local, Inner=Shared)
Boot=(Type=Boot, Filename=%GAMEDIR%DerivedDataCache/Boot.ddc, MaxCacheSize=1024)
Local=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, PurgeTransient=true, DeleteUnused=true, UnusedFileAge=34, FoldersToClean=-1, Path=../../../Engine/DerivedDataCache)
Shared=(Type=S3, Manifest="../../../Project/Build/S3DDC.json", BaseUrl="http://<your-bucket>.s3.<region>.amazonaws.com/", Region="<region>", AccessKey="<access-key>", SecretKey="<secret-key>")
[NoS3DDC]
MinimumDaysToKeepFile=7
Root=(Type=KeyLength, Length=120, Inner=AsyncPut)
AsyncPut=(Type=AsyncPut, Inner=Hierarchy)
Hierarchy=(Type=Hierarchical, Inner=Boot, Inner=Pak, Inner=EnginePak, Inner=Local, Inner=Shared)
Boot=(Type=Boot, Filename=%GAMEDIR%DerivedDataCache/Boot.ddc, MaxCacheSize=1024)
Local=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, PurgeTransient=true, DeleteUnused=true, UnusedFileAge=17, FoldersToClean=-1, Path=../../../Engine/DerivedDataCache)
Shared=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, DeleteUnused=true, UnusedFileAge=19, FoldersToClean=-1, Path=R:\SharedDDC, EnvPathOverride=UE-SharedDataCachePath)
AltShared=(Type=FileSystem, ReadOnly=true, Clean=false, Flush=false, DeleteUnused=true, UnusedFileAge=19, FoldersToClean=-1, Path=R:\SharedDDC, EnvPathOverride=UE-SharedDataCachePath2)
Pak=(Type=ReadPak, Filename=%GAMEDIR%DerivedDataCache/DDC.ddp)
EnginePak=(Type=ReadPak, Filename=../../../Engine/DerivedDataCache/DDC.ddp)
注意 S3DDC 配置里的 AccessKey/SecretKey 这类凭据绝不要直接写进会进版本控制的 ini,上面已替换为占位符。
启动编辑器时用 -ddc=NoS3DDC 指定不走 S3:
set rootPath=E:\MyEngineRoot
start %rootPath%\UnrealEngine\Engine\Binaries\Win64\UnrealEditor.exe %rootPath%\UnrealEngine\Project\MyProject.uproject -ddc=NoS3DDC
改不了客户端 ini 时的变通
如果客户端的 ini 把路径写死成某个盘符(比如 R:\),但你又不能改 ini,可以把共享路径映射成那个盘符:
Win+R打开 cmd。- 执行
net use R: <YourSharedDDCPath>。 - 检查能否访问
R:。
注意不要手动在 R: 里增删改文件。
不改 ini、直接设本地 DDC 路径也可以用 setx:
setx UE-SharedDataCachePath \\<nas-server>\NASShare\MyProjectDDC
方式二:ZenServer 作为 Shared DDC(实验性)
用新的 Zen Storage 服务器架构替代网络文件共享做 DDC 存储。相比老的文件共享,它更能容忍延迟、优化了到远程机器的 DDC 网络通信,而且不再在 DDC 存储层做同步 IO。
在高负载环境(比如构建农场)官方推荐这种方式,因为相比普通文件共享(SMB)和 Cloud DDC,它能扛显著更高的请求率。
需要提醒的是,目前 ZenServer 还没有身份验证机制(未来可能会加),它面向的是受信环境,比如办公室局域网或 VPN,凡是能连到 ZenServer 的用户都有完整的读/写/删权限。
安装 ZenServer 为 Windows 服务
最简单的方式是 zenserver.exe --install。zenserver 进程可以用 --config [配置文件路径] 接收配置文件,配置控制默认数据目录、垃圾回收参数、网络配置等。配置示例可在 EpicGames 的 GitHub 仓库找到(zen 仓库下的 upstream-config-templates/zen_config.lua.j2,访问仓库需先按 UE on GitHub 页面的说明操作)。
关于共享路径几个要点:
- 想改 Shared DDC 路径,设上面提到的
UE-SharedDataCachePath。但绝不要把它设成本地路径,那样你机器上会同时有 Local 和 Shared 两份缓存,占双倍磁盘、毫无收益。 - 如果用的是 Zen Storage 类型 DDC,可以用环境变量
UE-ZenSharedDataCacheHost=hostname(Mac 上UE_ZenSharedDataCacheHost)改主机(注意是改 host,不是 path)。
完整步骤(结合 UE5.5 实测):
- 把 Zen 工具复制到一个安装目录:
robocopy \Engine\Binaries\Win64 <ZenInstall> zenserver.* crashpad_handler.exe zen.*
- 在
<ZenInstall>下创建zen_config.lua,按需修改配置(结构见下文)。 - 设一个网络服务权限,允许通过任意 IP 访问本机 8558 端口(管理员命令提示符):
netsh http add urlacl url=http://*:8558/ user=<pc_user>
- 创建并启动服务(管理员命令提示符):
sc create "Zen Store" start=auto binpath="<ZenInstall>\zenserver.exe --config=<ZenInstall>\zen_config.lua"
sc failure "Zen Store" reset=60 actions=restart/60000
sc start "Zen Store"
- 验证:访问
http://localhost:8558/dashboard或http://<zen-server-ip>:8558/dashboard。
也可以直接 zenserver.exe --install --config <ZenInstall>\zen_config.lua.j2,装好后在 services 里能看到 Zen Store,右键 start 即可。如果不带 config,ZenShared 默认把数据放到 C:\ProgramData\Epic\Zen。
多个 ZenShared 服务(端口/Namespace 隔离)
实际部署里常见的需求是:一台构建机(BM)上搭几个 Zen Server,给不同项目分配端口、设项目专属 Namespace,统一管理多项目共享 DDC。有两条路。
A. 注册表改名 + sc create
zenserver.exe --install 只能创建名为 Zen Store 的服务,没法用参数改服务名。需要第二个服务时就得改注册表:
Win+R输入regedit打开注册表编辑器。- 导航到
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services。 - 找到
ZenServer项,右键导出为.reg。 - 用记事本打开
.reg,把所有ZenServer改成ZenServer2。 - 双击导入修改后的
.reg,在注册表里建出新的ZenServer2项。 - 用
sc创建新服务并指向不同配置文件:
sc create ZenServer2 binPath= "C:\ProgramData\Epic\Zen\Install\zenserver.exe --config C:\ProgramData\Epic\Zen\Install\zen_config2.lua.j2"
:: 删除服务
sc delete ZenServer2
B. winsw 包装(推荐,更省事)
用 winsw(从 winsw 官方 release 下载)把 zenserver.exe 包装成 Windows 服务,名字随便起。
单个服务:
- 准备好 Zen server:把
Zen\Install复制到C:\ProgramData\Epic\Zen\Install,修改里面的zen_config.lua.j2(主要改datadir、abslog、port)。 - 把 winsw 的 exe 改名为
ZenStorageServer.exe。 - 创建
ZenStorageServer.xml(路径按实际改):
<service>
<id>ZenStorageServer</id>
<name>Zen Storage Server</name>
<description>Service for running Zen Storage Server for Unreal Engine DDC.</description>
<executable>C:\ProgramData\Epic\Zen\Install\zenserver.exe</executable>
<arguments>--config C:\ProgramData\Epic\Zen\Install\zen_config.lua.j2</arguments>
<logpath>C:\ProgramData\Epic\Zen\windows_service\logs</logpath>
<logmode>rotate</logmode>
<onfailure action="restart" delay="10 sec"/>
</service>
- 安装并启动、验证:
ZenStorageServer.exe install
ZenStorageServer.exe start
ZenStorageServer.exe status
多个服务:
- 复制多份
zen_config_8558.lua.j2,分别改datadir、abslog、port。 - 复制多份
ZenStorageServer_8558.exe和ZenStorageServer_8558.xml,改 xml 里的<id>、<name>、<description>、<arguments>、<logpath>。 - 逐个
install/start。 - 设环境变量指向对应 IP:端口,例如
UE-ZenSharedDataCacheHost=<zen-server-ip>:8559。
配端口前先查端口是否被占用:
netstat -ano | find "8558"
端口范围是 0 到 65535,最好选 1024 到 49151 之间,避开系统服务和临时端口;同时确认防火墙放行。winsw 方式有个好处:不需要开文件夹共享权限,文件可以直接写进 Zenserver 指定的 share 路径。
多个 Namespace(同一 server 同一端口隔离多项目)
只想用一台 server、一个端口,靠 Namespace 隔离多个项目时,只需启一个 ZenShared 服务,然后改 Games\Config\DefaultEngine.ini:
[StorageServers]
Shared=(Host=<zen-server-ip>:8559, Namespace="project_name.ddc", EnvHostOverride=UE-ZenSharedDataCacheHost, CommandLineHostOverride=ZenSharedDataCacheHost, DeactivateAt=60)
设了 EnvHostOverride=UE-ZenSharedDataCacheHost 后,环境变量 UE-ZenSharedDataCacheHost 就能覆盖该值,否则覆盖不了。CI 里可以这样注入(Jenkins 示例):
stage('BuildCookRun'){
steps{
script{
withEnv(["UE-ZenSharedDataCacheHost=<zen-server-ip>:8558"]){
...
如果写入量很大,单台服务器可能成为瓶颈,这时可以考虑负载均衡,把请求分到多个实例上。
编辑器连接 ZenShared
打开编辑器时默认会启动 zenserver 并连 ZenLocal DDC。如果在 Games\Config\DefaultEngine.ini 里配了 Shared,打开编辑器时就会默认连到 ZenShared。
实测的一个坑:如果想在编辑器内直接填一个共享文件夹路径(比如 \\<nas-ip>\ZenCacheShared\8558\Data)来连 ZenShared,结果会在该 Data 目录下生成 Buckets、Content、TestData,也就是说它并没有真正连到 ZenShared 服务,而是把那个目录当成了普通文件系统 Shared。要真正连 Local DDC,得先禁用 zenserver。
zen_config.lua 结构
ZenServer 的 Lua 配置分几个段。下面按段说明。
服务器配置(server):
server = {
dedicated = true,
datadir = "d:\\ZenCacheShared",
abslog = "d:\\local.log",
debug = false,
sentry = {
allowpersonalinfo = true,
}
}
dedicated:true 表示专用服务器。datadir:数据目录。abslog:日志文件位置。debug:是否启用调试。sentry.allowpersonalinfo:是否允许向 Sentry 发送个人信息。
网络配置(network):
network = {
httpserverclass = "httpsys", -- httpsys|asio
port = 8558,
}
httpserverclass:HTTP 服务器类,httpsys或asio。port:监听端口,默认 8558。
垃圾回收配置(gc):
gc = {
intervalseconds = 28800, -- 每 8 小时
lightweightintervalseconds = 3600, -- 每小时
cache = {
maxdurationseconds = 864000, -- 10 天
}
}
缓存配置(cache):
cache = {
enable = true,
accesslog = false,
upstream = {
upstreamthreadcount = 4,
policy = "disabled", -- readwrite|readonly|writeonly|disabled
jupiter = {
name = "DefaultJupiterInstance",
url = "{{upstream_url}}",
oauthprovider = "{{upstream_auth_server}}",
oauthclientid = "{{upstream_client_id}}",
oauthclientsecret = "{{upstream_auth_token}}",
namespace = "ue.ddc",
ddcnamespace = "ue.ddc",
}
},
memlayer = {
targetfootprint = 1073741824, -- 1 GB
triminterval = 120, -- 最多每 2 分钟
maxage = 172800, -- 2 天
}
}
upstream 段是把这台 Zen 接到上游(比如 Cloud DDC / Jupiter)的配置,policy 控制上游读写策略,disabled 即不连上游。memlayer 是内存层,targetfootprint 是每个 namespace 内存层的目标占用,triminterval 是修剪间隔,maxage 是缓存项在内存层的最大年龄。
zenserver 常用命令行参数
zenserver [OPTION...],挑实测会用到的列一下:
常规:
--dedicated:专用服务器模式。-d, --debug:调试模式。--clean:启动时清除所有状态。--data-dir arg:持久化根目录。--config arg:Lua 配置文件路径。--install/--uninstall:安装/卸载为 Windows 服务。
网络:
--http <class>:HTTP 实现(asio|httpsys|null),默认 httpsys。-p, --port <port>:HTTP 端口,默认 8558。--http-forceloopback:强制使用本地环回接口。
缓存/上游:
--upstream-cache-policy:上游缓存策略(readwrite|readonly|writeonly|disabled)。--upstream-jupiter-url arg:Jupiter 实例 URL。--upstream-zen-url arg/--upstream-zen-dns arg:上游 Zen 服务器 URL / DNS。
GC:
--gc-enabled:是否启用 GC,默认启用。--gc-interval-seconds arg:GC 间隔,默认 3600 秒。--gc-cache-duration-seconds arg:缓存项被驱逐前的最大持续时间,默认 1209600 秒(14 天)。--gc-low-diskspace-threshold arg:允许写盘的最小空闲空间。
各组合的 Clean Cook 实测
为了搞清楚不同 DDC 组合的差别,做了一组 Clean Cook 测试,对比无缓存(首次)和有缓存(二次)的耗时。
| 组合 | 无缓存首次 | 有缓存二次 | 缓存文件路径 | 文件格式 |
|---|---|---|---|---|
| Local(文件系统) | 27min 16s | 11min 36s | Engine\DerivedDataCache\ | .udd |
| ZenLocal | 27min 17s | 11min 57s | ...\Common\Zen\Data | .ucas |
| ZenLocal + ZenShared | 18min 33s(ZenShared 无缓存 11min 57s) | 11min 21s | ...\ZenCacheShared\... | .ucas |
| ZenLocal + Shared(文件系统) | 31min 2s(Shared 无缓存 13min 52s) | 11min 7s | ...\Shared DDC\... | .udd |
几点观察:
- 完全无缓存时,Local 和 ZenLocal 的首次 cook 耗时基本一样(都在 27min 出头),Zen 的收益不在首次生成,而在后续命中和共享。
- 接上 ZenShared 或 Shared 后,如果共享端已经有别人 cook 好的缓存,首次耗时能从 27min 砍到 12 ~ 14min,这就是共享 DDC 的价值。
- 二次(缓存齐全)几乎都收敛到 11min 左右,差异不大。
- Zen 类型的缓存文件是
.ucas,文件系统类型是.udd。
Troubleshooting
显卡驱动导致 Editor 起不来
用 UGS 打开 UE5.4 的 Editor 时,一台 GTX 1660 的机器会在准备阶段报错起不来。升级显卡驱动后能启动;换一台 RTX 3080 也能直接启动。所以遇到 UE5.4 Editor 启动失败、又指向 GPU/驱动的报错时,先升级显卡驱动。
删除指定 DDC 文件(排查 Cook 死循环 / soft lock)
实测环境 UE5.2。Cook 阶段出现 soft lock:cook 日志显示一直在循环烘焙某几个文件,无限循环卡死。处理办法是定位到出问题的 DDC 文件然后删掉,让引擎重新生成。
- 启动 Editor 时打开 DDC 日志,加参数
-logcmds="LogDerivedDataCache Verbose":
start %TargetEngine%\Binaries\Win64\UnrealEditor.exe %TargetProject%\MyProject.uproject -logcmds="LogDerivedDataCache Verbose"
- 在编辑器里找到出错的文件,右键
Asset Actions → Reload。 - 双击打开该文件,查看日志,用
LogDerivedDataCache过滤,日志里会显示 DDC 的具体路径,按路径删掉对应的 DDC 文件即可。
DDC 文件命名规则:文件名的第 1、2 位是第一层文件夹名,第 3、4 位是第二层文件夹名。知道这个规则就能从日志里的 key 反推出磁盘上的路径。
一些失败的测试记录
这些是我试过、但没走通的路子,记下来省得以后再踩。
单击直接运行 zenserver.exe:启动后再 cook,连不上,访问不了。Local Zen 还是得靠编辑器拉起来,手动单跑这个 exe 对 cook 不起作用。
直接把 DataPath 改成共享/NAS 路径:比如把 DataPath 指到 \\<nas-ip>\ZenCacheShared\8558\Data,结果写不进去。即便把共享挂载到本地盘符,依然写不进去,数据会被写回本地的 C:\ProgramData\Epic\Zen\Data。再改回默认路径时,DDC 会写到 ...\Common\Zen\Data,但 C:\ProgramData\Epic\Zen\Data 不会被自动删除,得手动清。结论:Local Zen 的 DataPath 不能直接指共享路径,要共享必须走 ZenShared 服务。
改 [Zen.ConnectExisting] 的 host/port:无论改 host 还是 port 都不生效。
- host:最终都会指向
[::1](IPv6 环回地址,等价于 IPv4 的127.0.0.1,意味着服务跑在本机)。即便删掉--http-forceloopback也还是回到[::1]。 - port:要在这里指定才会生效,而且只对 ZenLocal 生效。
实践建议
综合下来,团队多项目共享 DDC 的一套可落地方案:
- 选一台构建机搭几个 Zen Server;
- 给不同项目合理分配端口,并设项目专属 Namespace;
- 统一管理多项目的共享 DDC。