ZenServer と UnrealCloudDDC

 毎日のDDC Pakのコピーが面倒臭くてしょうがないの巻

この記事はUnreal Engine (UE) Advent Calendar 2025 のシリーズ3、12月22日分に向けて書いたものです。

Linux 版 ZenServer と UnrealCloudDDC をローカルで立てて DDC 読込がどの程度改善するか、検証してみました。

DDC とは何か

DDC とは Derived Data Cache の略で、UE がアセットを読み込む際にCook(プラットフォーム向けの変換処理)したデータを キャッシュとして保持しておく仕組みです。

なんのこっちゃようわからん、という方は公式のサンプルプロジェクトを初めてUEエディタで開いた時の様子を思い浮べて下さい。 エディタの右下にPreparing...とプログレスバーが延々と表示され続け、その間エディタの操作が重くてやってられんわ…という状態になっていた事と思います。 その時にUEが必死に生成していたデータがDDCです。 2回目以降のエディタ起動時にはすぐに操作できるようになっているはずですが、それは生成済みのDDCを読み込んでいるからです。

Unreal Fest Gold Coast 2024 の講演Improving Development Iterations: A Deep Dive into Enhanced Feature のスライドに、DDCに保存されるデータの内容が記載されています。

大量のアセットを扱うUEのプロジェクトでは、毎晩ビルドマシンでDDC Pak([プロジェクト名].ddp)が生成されてサーバにアップロードされており、 まず手元のDerivedDataCacheフォルダにコピーしてからUEを起動するのが日課だった…という方もおられるのではないでしょうか。 結構なサイズがあって(リモート勤務の立場だと特に)ダウンロードする時間も結構かかる割に、毎日どんどんアセットが追加されていく状況ではすぐに古くなってしまいます。 更新分だけ入手できればいいのに、全てのDDCがパックされているデータを丸ごとダウンロードするのは非効率的です。 そのため、DDC Pakのダウンロードは初回に留め、毎日のDDC更新は手元で待つ…というのが現実的な運用かと思います。

ZenServer の登場

UE5.4の頃に導入されたZenServer(Zen Store)は、DDCをキャッシュし共有するためのサーバです。 UE5.5のリリースノート によると、DDCの共有を目的とした ZenServer の使用が Production Ready になっています。UEエディタを使用している間は常時ローカルで起動するようになっており、 手元で生成されたDDCはすでにローカルのZenServerで保持されています。 これまでのファイルシステムにDCCを保存する方法に比べて、小さなDDCの読み書きがサーバでまとめられる事でパフォーマンスが向上します。

UEエディタの右下にあるZenServerのアイコンをクリックして、Launch Dashboard を表示すると、ローカルのZenServerの状態が表示されます。

さらに、Browseの所のリンクをクリックするとブラウザでローカルのZenServerのダッシュボードでキャッシュされているDDCデータを表示することができます。

この画面ではDDCのサイズを確認したり、削除をすることができます。

UEエディタから自動起動されるZenServerはあくまでローカル用ですが、別途ZenServerを立てて複数のPC間でDDCを共有する事も可能です。 DDCの共有はアセットごとに行われるため、手元に存在しないDDCだけをリモートのZenServerから取得する仕組みのため無駄がありません。

ZenServer をLinuxで立てる

公式ドキュメント では Windows上に立てる手順が紹介されていますが、Linux版も試してみたら同じように動作したのでその手順を紹介します。 (ただし、production-readyなのはWindows版のみである事に注意して下さい) 環境は Windows11 Pro 内の WSL2 (Ubuntu 22.04LTS) を使用しています。実際に運用する時は手頃なLinuxサーバに立てるのが良いでしょう。

Linux 版 ZenServer の入手

Linux版 ZenServer の実行ファイルの入手方法は2種類あります。

  • 公式のLinux版UnrealEngineからダウンロードできる Linux_Unreal_Engine_5.7.1.zip に同梱されています。 zip ファイル内の Engine/Binaries/Linux/zenserver Engine/Binaries/Linux/zen にあります。 バージョンはUE5.7.1リリース時点のものとなります。
  • 最新版は githubのEpicGames/zenリポジトリ内のReleasesページから入手できます。 ただし、最新版は本番投入前に独立した環境で検証すること、と明記されています。

ZenServer の設定ファイルの場所

src/zencore/filesystem.cpp によると、configファイルの配置場所は以下の通りです。

  • Windows版の場合、C:\ProgramData\Epic\Zen\ があればそちらで、なければカレントフォルダです。
  • Linux版の場合、ソースによると~/.zen/Data を参照するように読めるのですが、実際に動作確認する限りはカレントディレクトリになるようです。

デフォルトのconfigファイル名は、src/zenserver/config/config.cpp によると zen_cfg.lua です。 ( 公式ドキュメント にある zen_config.lua とは異なる事に注意して下さい。公式ドキュメントではWindowsサービスを作成する時に --config オプションにより明示的にconfigファイル名を指定しています)

WSL2 のUbuntuに ZenServer を手動インストールする

UbuntuにZenServerをインストールする手順はこちらになります。ZenServer実行用の専用ユーザー zen を作成し、ホームディレクトリのbinディレクトリにインストールします。

# zen ユーザーとそのホームディレクトリを作成、ログインシェルをbashに設定します。
$ sudo useradd -m -s /bin/bash zen

# zen ユーザーに切り替えます。
$ sudo su - zen

# ホームディレクトリ直下にbinディレクトリを作成します。
$ mkdir bin

# f:/tmp にある zenserver と zen をbinディレクトリにコピーします。
$ cp /mnt/f/tmp/zenserver /mnt/f/tmp/zen bin/ 

下記の内容で /home/zen/bin/zen_cfg.lua を作成して下さい。

-- Zen Store Lua config

server = {
    dedicated = true,
    datadir = "/home/zen/.zen/Data",
    abslog = "/home/zen/.zen/Data/logs/zenserver.log",
    debug = false,
    sentry = {
        disable = false,
        allowpersonalinfo = false,
    }
}
network = {
    httpserverclass = "httpsys", -- httpsys|asio
    port = 8558,
}
gc = {
    intervalseconds = 28800, -- every 8 hour
    lightweightintervalseconds = 3600, -- every hour
    cache = {
        maxdurationseconds = 864000, -- 10 days
    }
}
cache = {
    enable = true,
    accesslog = true,
    upstream = {
        upstreamthreadcount = 4,
        policy = "disabled", -- readwrite|readonly|writeonly|disabled
    },
    memlayer = {
        targetfootprint = 1073741824, -- 1 GB
        triminterval = 120, -- max every 2 minutes
        maxage = 172800, -- 2 days
    }
}

systemd サービス化

ついでにsystemdのサービスとして動かす設定もしてしまいましょう。/lib/systemd/system/zenserver.service を作成し、下記の内容をコピペして下さい。 設定ファイルをカレントディレクトリから読み込むため、WorkingDirectoryの設定が重要です。

[Unit]
Description=ZenServer for UnrealEngine
After=network.target

[Service]
Type=simple
ExecStart=/home/zen/bin/zenserver
WorkingDirectory=/home/zen/bin
Restart=always
User=zen

[Install]
WantedBy=multi-user.target

設定が終わったら、systemdサービスに登録して起動します。

$ sudo systemctl enable zenserver
Created symlink /etc/systemd/system/multi-user.target.wants/zenserver.service → /lib/systemd/system/zenserver.service.
$ sudo systemctl start zenserver

無事に起動すると、ブラウザから http://[WSL2 UbuntuのIPアドレス]:8558 を開くと下記のようなダッシュボードが表示されます。

うまく表示されない場合は、WSL2特有の問題を踏んでいる可能性があるため次の節を確認して下さい。

(WSL2のみ必要) systemctl を使おうとしてエラーが出たときの対処

もし下記のようなエラーが出た時は、WSL2特有の対応が必要です。

System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down

WSL2ではデフォルト状態でsystemdが無効化されているため有効化の対応が必要です。 WSL2 のUbuntu内において、/etc/wsl.conf に下記内容を追記します。

[boot]
systemd=true

続いてホスト側のWindows11上でPowerShellを管理者権限で起動し、下記コマンドを実行してWSL2を終了します。

> wsl.exe --shutdown

再度WSL2のUbuntuを起動しすると、systemctl が動作するようになります。

UEプロジェクトからリモートZenServerを使うよう設定する

ローカルZenServerはデフォルトの状態で使う設定になっていますが、リモートZenServerを使うには別途プロジェクト設定が必要です。

UEプロジェクトのConfig/DefaultEngine.ini に下記StorageServersセクションを追記して下さい。(IPアドレスやプロジェクト名はお手元の環境に合わせて適宜書き換えて下さい)

[StorageServers]
Shared=(Host="http://[リモートZenServerのIPアドレス]:8558”, Namespace="[プロジェクト名]", EnvHostOverride=UE-ZenSharedDataCacheHost, CommandLineHostOverride=ZenSharedDataCacheHost, DeactivateAt=60)

このiniファイル回りの仕組みを深掘りしたい方は、Engine/Config/BaseEngine.ini のコメント部分が参考になると思います。

また、プロジェクト設定のPackagingでUse Io StoreUse Zen Server as cooked output storeを有効にして下さい。(Io Storeの方はデフォルトで有効になってるはずです)

この設定は /Config/DefaultGame.ini には以下のように追記されています。

[/Script/UnrealEd.ProjectPackagingSettings]
bUseZenStore=True

正しく設定できていれば、UEエディタ起動時にCache Statisticeを開くとZen Remoteが表示されるようになります。

UnrealCloudDDC をローカルに立てる

UnrealCloudDDC はAWSやAzure等のクラウド上に立てるDDCサーバです。 複数の拠点でUE開発を行なうような大規模なプロジェクトでの使用を想定されており、クラウドストレージへのデータ保存やOpenIDConnect(OIDC)による認証などセキュリティ面の対策も考慮されています。

UEエンジンソースには検証用にdocker-compose用の設定ファイルが同梱されているので、Docker Desktop を使ってローカルで起動する事ができます。 コマンドプロンプトを開いてエンジンソースの Engine/Source/Programs/UnrealCloudDDC ディレクトリに移動し、下記コマンドを実行して UnrealCloudDDC をビルド・実行します。

> docker-compose -f Composes\docker-compose.yml -f Composes\docker-compose-aws.yml up --build

手元で実行した所、下記エラーが表示されました。System.Linq.Async のバージョンが依存関係で競合しているようです。

25.23   Restored /app/Programs/UnrealCloudDDC/Jupiter.Common/Jupiter.Common.csproj (in 23.69 sec).
25.24 /app/Programs/UnrealCloudDDC/Jupiter/Jupiter.csproj : error NU1605: Warning As Error: Detected package downgrade: System.Linq.Async from 6.0.3 to 6.0.1. Reference the package directly from the project to select a different version.
25.24 /app/Programs/UnrealCloudDDC/Jupiter/Jupiter.csproj : error NU1605:  Jupiter -> Jupiter.Common -> EpicGames.Horde -> System.Linq.Async (>= 6.0.3)
25.24 /app/Programs/UnrealCloudDDC/Jupiter/Jupiter.csproj : error NU1605:  Jupiter -> System.Linq.Async (>= 6.0.1)

エラー内容に従い、Jupiter/Jupiter.csproj 内に記載されている System.Linq.Async のバージョンを6.0.1→6.0.3に書き変えます。

    <PackageReference Include="Crc32.NET" Version="1.2.0" />
    <PackageReference Include="K4os.Compression.LZ4" Version="1.3.6" />

    <PackageReference Include="CassandraCSharpDriver" Version="3.19.5" />

    <PackageReference Include="System.Linq.Async" Version="6.0.1" /> <!-- ここを 6.0.3 に書き変える -->

    <!-- Embeds git information into the build process 
        Enable this if you are on git to embedd the git hash into the build 
        Produces warnings while source is in perforce -->

正常に起動すると、http://localhost/health/live にアクセスした時にこのような表示になります。 ZenServerのようなダッシュボードはなく、あまりにもシンプル過ぎる表示ですね…。

APIの仕様についてはUnrealCloudDDCのディレクトリを漁ったものの見つけられなかったため、各自ソースコードを読んで下さい。

  • Engine/Source/Programs/UnrealCloudDDC/Jupiter/Controllers/ReferencesController.cs が参照関係のREST API
  • Engine/Source/Programs/UnrealCloudDDC/Jupiter/Controllers/BlobController.csがデータ制御関係のREST API

になるようです。 Engine/Source/Programs/UnrealCloudDDC/Jupiter/Tests/Functional/Objects/ReferencesTests.cs 辺りによると、キャッシュをクリアするには下記HTTPリクエストを投げる必要があるようです。

> curl -X DELETE http://localhost/api/v1/refs/[Namespace名]
> curl -X DELETE http://localhost/api/v1/s/[Namespace名]

UEプロジェクトからリモートUnrealCloudDDCを使うよう設定する

さらに、UnrealCloudDDCを使うようにするにも設定が必要ですが、公式のドキュメントを参考に設定してもうまく動作しなかったため、 以下はソースコードを読んた上での独自の解釈に基づく記述となるためご了承下さい。

Engine/Source/Programs/UnrealCloudDDC/Engine/Source/Developer/DerivedDataCache/Private/HttpCacheStore.cpp の3519~3560行目を読むと、

  • Hosthttp://localhost または https://localhost の時は OAuth 関係の処理をスキップしようとしている形跡があるが、3519行目のロジックミスと思われる処理により必ず通ってしまう
  • OAuthProviderOAuthProviderIdentifierOAuthAccessTokenのパラメータが必須
  • OAuthProvider http://localhost であれば、OAuthProviderIdentifierOAuthAccessToken` の値は何でもよい

ということで、DefaultEngine.ini に下記を追記する事で UnrealCloudDDC に接続できるようになりました。

[StorageServers]
Cloud=(Host="http://localhost", Namespace="[プロジェクト名]")

[InstalledDerivedDataBackendGraph]
Cloud=(Type=Cloud, ServerID=Cloud, EnvHostOverride=UE-CloudDataCacheHost, CommandLineHostOverride=CloudDataCacheHost, CommandLineOAuthSecretOverride="CloudDataCacheOAuthSecret", OAuthAccessTokenEnvOverride="UE-CloudDataCacheAccessToken", EnvHttpVersionOverride="UE-CloudDataCacheHttpVersion", CommandLineHttpVersionOverride="CloudDataCacheHttpVersion", EnvOAuthProviderIdentifierOverride="UE-CloudDataCacheOAuthProviderIdentifier", CommandLineOAuthProviderIdentifierOverride="CloudDataCacheOAuthProviderIdentifier", OAuthProvider="http://localhost", OAuthProviderIdentifier="hogehoge", OAuthAccessToken="hogehoge")

[InstalledDerivedDataBackendGraph] の箇所はランチャービルドのUEの場合になります。ソースビルドの場合は [DerivedDataBackendGraph] に変更して下さい。 また、このあたりについての仕組みについても深掘りしたい方は、Engine/Config/BaseEngine.ini のコメント部分をご覧下さい。

CloudDDC の接続に成功すると UE エディタのログに下記のような内容が出力されます。

[2025.12.20-23.53.49:874][  0]LogDerivedDataCache: Display: Cloud: Using session id 934f590988ba43ff00000000.
[2025.12.20-23.53.49:875][  0]LogDerivedDataCache: Cloud: Skipping authorization for connection to localhost.
[2025.12.20-23.53.49:889][  0]LogDerivedDataCache: Display: Cloud: HTTP DDC: Healthy

参考までに、うまく行ってなかった時のログはこんな感じでした。

[2025.12.20-08.15.06:042][  0]LogDerivedDataCache: Warning: Cloud: Missing required parameter 'StructuredNamespace', falling back to 'Hillside57'
[2025.12.20-08.15.06:042][  0]LogDerivedDataCache: Error: Cloud: At least one OAuth configuration must be provided and valid. Options are 'OAuthProvider', 'OAuthProviderIdentifier', and 'OAuthAccessTokenEnvOverride'
[2025.12.20-08.15.06:042][  0]LogDerivedDataCache: Unable to find inner node Cloud for hierarchy Hierarchy.

HillsideサンプルでローカルZenServer・リモートZenServer・UnrealCloudDDCを有効にした時のキャッシュ状況はこんな感じになりました。

ローカルZenServer・リモートZenServer・UnrealCloudDDC は同時に接続する事が可能です。 Read/Write の挙動を見ていると、取得時間が短い方(つまりローカルZenServer)から優先して取得し、書き込みは3つに対し同時に行われています。

HillsideサンプルプロジェクトでのDDCの効果

Hillsideサンプルプロジェクトを開いた時のDDC生成/読込時間を計測しました。 測定環境は以下の通りです。

種別名称
OSWindows11 Pro 25H2
CPURyzen7 9700X
MemoryDDR5 64GB
GPUGeForceRTX3060 12GB
SSD(OS)Crucial P2 2TB
SSD(UE)ADATA LEGEND800 2TB
SSD(Project)ASpacer AS2280P4X 2TB

測定方法は、Hillside(UE5.7)サンプルプロジェクトを開いた後、UEエディタが表示され右下にPreparing...プログレスバーが表示されている間の時間をキャプチャ動画から計測しました。 GUIの表示タイミングに基づいた計測のため正確性に欠ける点はご了承下さい。 (当初はuprojectファイルをクリックしてからPreparingが消えるまでの時間を測定していましたが、プロジェクト自体のロード時間にディスクキャッシュの影響と思われるバラつきがあったため見送りました) DDCの読込元の切り替え方法は、ローカルZenServerまたはリモートZenServerのキャッシュを削除(ダッシュボードからdrop)してUEエディタを再起動する、という方法で行いました。

読込元のDDC時間(時:分:秒)
ローカルZenServerから読込00:05:53
リモートZenServerから読込00:06:17
UnrealCloudDDCから読込00:10:55
DDC全削除した状態から生成23:05:77

読み込み時間はやはりローカルZenServerが最速で、次にリモートZenServer、UnrealCloudDDCが続く結果となりました。 あまり差がないのは同じPC上で実行するWSLやDockerで実行しているためですね。 いずれもゼロから生成する時にかかった23分に比べて格段に速い事がわかります。

職場内にリモートZenServerを立てる方法なら比較的簡単に導入できると思いますので、試してみて下さい。 (チームメンバー全員がリモートのようなチーム開発でも、小規模であればレンタルVPSを借りてZenServerを稼動、SSH tunnelingで接続するのもありでは…とは思っていますが、 ただのロートルの戯言です)

検証から除外した内容

また、上記の検証に含まれてない内容に1つ触れておきます。 ビルドマシン上でのバッチ処理で DDC を生成しておくには下記コマンドを使用します。

> Engine\Binaries\Win64\UnrealEditor.exe ProjectName -run=DerivedDataCache -fill

ところが、この方法で ZenServer に登録されるDDCのサイズが UE エディタを起動した時と比べて明らかに少ないようです。 この後にUEエディタを起動すると、Preparing...のGUIは依然表示され続けているため、十分なDDCの生成ができてないと思われます。

この問題は別途調査していきたいと思います。

UnrealCloudDDC をクラウドに立てる方法

上でも書いたように、UnrealCloudDDC は本来AWSやAzureなどのクラウド上に DDC サーバを立てて共有する仕組みです。

AWSへのデプロイ方法は Engine/Source/Programs/UnrealCloudDDC/Bootstrapping/AWS/readme.md に記載されているスクリプトを叩くだけですが、中々恐ろしい事が書いてあります。

This generates a bit of hardware that has flat costs so you should expect a run of this to end up with a cost about $1600 / month broken down like this:

  • i3en instances - $700 (these are used to host the cloud ddc api)
  • i3 instances - $120 (this hosts the scylla monitoring and mangement services)
  • i4i instances - $500 (this hosts the actual scylla database)
  • c5 instances - $130 (used to host the cloud ddc worker)

1月当たり1600ドル(1ドル157円換算で25万円)もかかるシステム構成になるそうな。 EKSクラスタを立てるのでそういうもんなんでしょうか…。

別案として、AWSが Cloud Game Development Toolkit なるものを github にて公開しています。 UnrealFest Seattle 2024 や GDC 2025 の講演で紹介されていたようです。

ゲームのクラウドビルドで必要になりそうなインフラ構成のモジュールをterraformのコードとして公開しており、下記のサンプルが用意されています。

UnrealCloudDDC はこのようなシステム構成でデプロイされます。 (画像は githubリポジトリのここ からお借りしています)

手元で実行するには、githubのアクセストークンとRoute53に登録済みのドメインが必要になります。 試しに terraform apply してみた所、Amazon EKSの addon が有効にならずデプロイに失敗してしまいました。

20分のタイムアウトが経過して失敗と判定されるまでにも、下記のEC2インスタンスが起動されているためもりもり課金されていきます。

一月あたり2100ドルを超える勢いなのでそっと destroy してしまった(涙)のですが、また機会があれば試してみたいと思います。

文責:ともたこ/Tomotaka Ogino Twitter/github/Qiita