地形生成の分担
地形生成で一番重い処理を、暗号化した通信で別のマシンに計算してもらう。結果はまったく同じ。
地形生成はいくつかの段階に分かれています。一番重い ノイズ の段階では、土地の形(どこが石・空気・水・溶岩か、洞窟や帯水層)を決めます。 この計算に必要なのはシード・ワールドの設定・近くの構造物だけで、隣のチャンクやプレイヤーの行動には左右されません。だから別のマシンで計算できます。
分担を使うと、Storia サーバー(クライアント)は 1 台以上の ワーカー にノイズの計算を依頼します。ワーカーは計算したブロックを送り返し、 それ以外の処理はすべてメインサーバーに残ります。
Storia サーバー(プレイヤー、ワールド) Storia Worker(別のマシン)
構造物、地物、光 --- 依頼(チャンク+近くの構造物) --->
<--- 地形のブロック、高さマップ --- 地形ノイズ
移るもの・残るもの#
| 段階 | 処理する場所 |
|---|---|
| 構造物の開始点と参照 | メインサーバー |
| バイオーム | メインサーバー |
| ノイズ(地形の形、洞窟、帯水層) | 空いていれば ワーカー |
| 地表、洞窟の彫り込み、地物(木・鉱石)、光、スポーン | メインサーバー |
| ティックで動くものすべて | メインサーバー |
ノイズより後の段階は、隣のチャンクに左右されたり、50 ms のティック内に終わらせる必要があったりするので、メインサーバーに残ります。 ノイズは生成の中で一番大きな部分なので、これを移すだけで多くの CPU が空きます。
結果は常に同じ#
- 接続時の照合。 サーバーがワーカーに接続すると、両方がディメンションごとに同じ確認用チャンクを生成し、ハッシュを比べます。 完全に一致したディメンションだけを分担します。シード・データパック・Storia のビルドが違えばそのディメンションは断られ、理由がログに出ます。
- 検証。 ワーカーからの返事は、チャンクに反映する前に毎回チェックします。
- 自分で生成に戻る。 空いているワーカーがない、ワーカーが遅い(
timeout-ms)、接続が切れた、といったときは、そのチャンクを自分で生成するだけです。 止まったワーカーのせいでプレイヤーが待たされることはありません。 - 検証モード。 メインサーバーを
-Dstoria.verifyOffload=true付きで起動すると、分担したチャンクを自分でも生成して照合します。テストでは差異 0 件でした。
設定#
必要なもの:
- メインの Storia サーバー
- Java 25 が入った、手伝う側のマシン 1 台以上(Storia Worker のパッケージを使います)
- サーバーの設定を変えずにワーカーを増減したいなら Storia Relay(任意)
- 8 文字以上の共通の 合言葉
メインサーバー#
# storia.yml
offload:
mode: client
secret: "長くてランダムな合言葉"
workers:
- 192.168.0.20:25590
- 192.168.0.21:25590
再起動します。サーバーの読み込みが終わる(Done)と、分担が始まります。
ワーカー#
Storia Worker の手順に従います。要約すると、storia-worker-26.2.zip を展開し、メインサーバーのワールドフォルダを region・entities・poi を除いてコピーし、
同じ合言葉を設定して start-worker.sh を実行します。
リレーを使う場合#
Storia サーバー --\ /-- ワーカー A
>-- Storia Relay <---- ワーカー B
Storia サーバー --/ \-- ワーカー C
サーバーはリレーだけをワーカーとして登録し、ワーカーは自分からリレーに接続します。Storia Relay を参照してください。
動作の確認#
/storia offload
Client mode: 3120 chunks offloaded, 0 generated locally after a failure
generated locally: 41 (workers busy), 0 (blending with old terrain), 0 (upgraded chunk), 12 (no plain noise state)
192.168.0.20:25590: connected (encrypted), 6 threads, 7/24 in flight, 3120 done, 0 failed, avg 38.5 ms, dims [minecraft:overworld, minecraft:the_nether, minecraft:the_end]
| 自分で生成した理由 | 意味 |
|---|---|
| workers busy | すべての接続が満杯でした。ワーカーかスレッドを増やしてください。 |
| blending with old terrain | 古いバージョンの地形と接していて、なじませる処理が必要なチャンクです。 |
| upgraded chunk | 古いバージョンで途中まで生成されたチャンクです。 |
| no plain noise state | ワーカーに伝えられない種類のチャンクです。まれで、正常な動作です。 |
性能#
メインサーバー 3 コア、ワーカー 1 台(別の 3 コア)で 3,721 チャンクを事前生成した結果:
| 時間 | |
|---|---|
| メインサーバーだけ | 1分35秒 |
| メインサーバー+ワーカー 1 台 | 1分6秒(ノイズの 95% を分担、検証した 888 チャンクの差異 0 件) |
ワーカーを増やすほど速くなり、最後はメインサーバーに残る段階が上限になります。分担が効くのは 新しい地形(探索と事前生成)です。 エンティティやレッドストーンは速くなりません。
ポート#
ポートはマシンごとに自由に決められます。25590 は初期設定の値にすぎません。
| マシン | ポートを設定する場所 |
|---|---|
| ワーカー(待ち受け) | その storia.yml の offload.port |
| リレー | relay.properties の port= |
| メインサーバー | 開ける必要なし(自分から接続します)。offload.workers の各行に host:port を書きます。 |
| リレーを使うワーカー | 開ける必要なし。offload.relay: "host:port" にリレーのポートを書きます。 |
たとえば、ワーカー 2 台を別々のポートで動かす場合:
# ワーカー A(storia.yml)
offload:
port: 10000
# ワーカー B(storia.yml)
offload:
port: 10001
# メインサーバー(storia.yml)
offload:
mode: client
workers:
- 192.168.0.20:10000
- 192.168.0.21:10001
ポート転送も使えます。ルーターで外側のポート 10001 をワーカーの 25590 に転送しているなら、メインサーバーには外側のアドレスとポート
(203.0.113.5:10001)を書きます。
ネットワーク#
- 通信はワーカー(またはリレー)ごとに TCP 接続 1 本です。
- 1 チャンクあたりの通信量は小さく、圧縮もしています。LAN や、データセンター間の VPN が理想です。遅延が大きくても、1 件ごとの依頼が遅くなるだけで、サーバーは遅くなりません。
- すべて暗号化・認証されています。暗号化とセキュリティ を参照してください。