Skip to content

Storage und Map Streaming

ElGregor edited this page Aug 15, 2026 · 1 revision

Storage und Map-Streaming (B42)

Home · Zurück: Performance-Guide

Wie der Project-Zomboid-B42-Server die Welt auf die Platte schreibt und beim Spielen wieder streamt, welche Storage-Tiers in der Praxis sinnvoll sind, wie man Symptome misst und wann eine tmpfs/RAM-Disk eine Option ist. Diese Seite ist die deutschsprachige Adaption des englischen Storage-Guides b42-storage-map-streaming-guide.md aus dem Repo und übernimmt dessen Mess-Schwellen, Mess-Befehle und tmpfs-Skizze 1:1 mit Quellen-Label. Repo-Verhalten 1:1 aus dem Repo-Klon.

Label-Legende: (Repo-Default) = Wert/Pfad steht 1:1 im Repo. (Community- Quelle: ...) = extern belegt. (Heuristik) = begründete Eigen-Empfehlung. The Indie Stone (TIS) veröffentlicht keine offiziellen IOPS- oder Latenz-Specs — Vendor-Zahlen sind Marketing, keine B42-Anforderung.

1. Warum B42 speicherintensiv ist

B42 bringt zwei Eigenschaften mit, die den Storage-Druck gegenüber B41 deutlich erhöhen (Heuristik, abgeleitet aus dem EN-Storage-Guide):

  • Bis zu 32 Etagen Voxel-Daten pro Chunk — beim Aufzugfahren oder beim Betreten einer Stadt mit Hochhäusern lädt der Server entsprechend mehr Voxel-Slices nach (Heuristik; Symptomlage: Community-Quelle, GTX Gaming).
  • Cell-/Chunk-Streaming + periodische Autosave-Bursts — kontinuierliche Random-Reads beim Cell-/Loot-/Container-Zugriff, dazu alle SaveWorldEveryMinutes=15 Minuten (Repo-Default aus servertest.ini.tmpl) ein Schreib-Burst (Heuristik, EN-Storage-Guide).
  • Dichte Basen konzentrieren Lese- und Schreibdruck — mehr Welt- und Container-Zustand wird gemeinsam abgerufen (Heuristik, EN-Storage-Guide).

Konsequenz: Storage ist auf B42 der häufigste Engpass, bevor CPU oder RAM ins Limit gehen (Heuristik, Performance- und Storage-Guide).

Laufzeit-Verzeichnisse

Wo der Server welche Daten hält. Pfade 1:1 aus dem Repo-Stand (Repo-Default, .env.example): die Repo-Defaults lauten /opt/pzserver/..., nicht /home/pzuser/... wie im EN-Guide. Die Spalte „EN-Guide" zeigt die pzwiki-Konvention, die der EN-Storage-Guide verwendet — das ist Community-Wissen, nicht Repo-Stand.

Zweck Repo-Pfad (Repo-Default) EN-Guide-Pfad (Community-Quelle: pzwiki)
Server-Install (Binaries, StartServer64.sh) ${PZ_HOME} = /opt/pzserver und ${PZ_SERVER_DIR} = /opt/pzserver/server (Repo-Default) /opt/pzserver/ oder steamapps/common/Project Zomboid Dedicated Server/
Konfiguration (INI, SandboxVars, Spawn) ${PZ_DATA_DIR}/Server/ = /opt/pzserver/Zomboid/Server/ (Repo-Default) ~/Zomboid/Server/
Multiplayer-Welt + Cell-Saves ${PZ_DATA_DIR}/Saves/Multiplayer/<world>/ (Repo-Default; Backup-Ziel Nr. 1) ~/Zomboid/Saves/Multiplayer/<world>/
Spielerbezogene Map-Daten ${PZ_DATA_DIR}/Saves/ (Repo-Default) ~/Zomboid/Saves/
Datenbankdateien ${PZ_DATA_DIR}/db/ (Repo-Default) ~/Zomboid/db/

~ im EN-Guide meint das Home des Server-Kontos; im Repo ist dieses Konto pzserver (aus PZ_USER=pzserver, .env.example). Beide Quellen bezeichnen also dasselbe logische Layout, nur an unterschiedlichen Pfaden.

2. Storage-Tiers und dokumentierte Symptome

Die folgende Tabelle übernimmt Symptome und Tiers aus dem EN-Storage-Guide und dem PDF-Handbuch (Kapitel 2) 1:1 und behält deren Labels bei (Community-Quelle/Heuristik). Es gibt keine offiziellen TIS-IOPS-Specs — Vendor-Zahlen sind Marketing (Community-Quelle, EN-Storage-Guide).

Tier Erwartetes B42-Verhalten Quelle/Label
HDD Dokumentiertes Symptomgebiet: lange Welt-Ladezeiten, stotterndes Cell-Streaming, Rubber-Banding, verzögerte Loot-/Inventar-Interaktion an stark frequentierten Orten Community-Quelle (Vendor-Angabe GTX Gaming)
SATA SSD Meist brauchbar für kleine Server mit moderater Population und wenigen dichten Basen; kann bei überlastetem Controller dennoch stocken Heuristik
NVMe (Consumer/Enterprise) Empfohlener Storage-Tier, da der Workload von latenzarmen Random-Reads profitiert Heuristik
NVMe Gen4/Gen5 RAID Von Hostern für PZ vermarktet; verbessert ggf. Aggregat, begründet aber kein B42-IOPS-Ziel Community-Quelle (Vendor-Marketing)

Eine SATA-SSD garantiert nicht automatisch Geschwindigkeit; ein NVMe kann hinter einem überlasteten Controller langsam wirken. Maßgeblich ist die Messung am Gerät, das die Live-Save-Struktur bedient (Heuristik, EN-Storage-Guide).

Dokumentierte Slow-Storage-Symptome (Community-Quelle, GTX Gaming, EN-Storage-Guide):

  • Loot-Lag um die 30 Sekunden an großen Basen
  • Rubber-Banding an großen Basen
  • Scheinbar endloses Laden der Welt beim Verbinden

Wichtig: Dieselbe Beobachtung kann von Spielern als „loot lag", „rubber-banding", „server lag" oder „slow world load" beschrieben werden — die Subsysteme sind oft unterschiedlich verantwortlich. Korrelation mit exaktem Zeitstempel ist Pflicht (Heuristik).

Symptome gegen andere Ursachen abgrenzen

Eine Lag-Beobachtung ist erst dann ein Storage-Verdacht, wenn andere Verursacher ausgeschlossen sind (Heuristik, EN-Storage-Guide). Die folgende Mini-Tabelle hilft bei der Schnelldiagnose:

Beobachtung Eher Storage Eher JVM/GC Eher Netzwerk
await & iowait beide hoch ja (Heuristik) nein nein
await hoch, iowait niedrig fraglich — eventuell Controller-Konflikt nein nein
GC-Pausen dominieren Log nein ja (Heuristik) nein
Spieler-Desync nur bei einem Client nein nein ja (Heuristik)
Lag exakt zum Save-Zeitpunkt (SaveWorldEveryMinutes=15) ja (Heuristik) nein nein
Lag beim ersten Betreten einer neuen Zelle ja (Heuristik) nein nein

3. Latenz-Schwellen (Heuristik, aus dem EN-Storage-Guide)

Die folgenden Schwellen sind Heuristik (definiert vom EN-Storage-Guide, nicht vendor-dokumentiert und keine offiziellen B42-Anforderungen). Sie sind Startpunkte für die Untersuchung, keine Garantien. Quelle: EN-Storage- Guide und PDF-Handbuch Kapitel 8 (Block 249–253) — Werte 1:1 übernommen.

Metrik (iostat -x / vmstat) Gesund Degradiert Kritisch Spielerisch sichtbar
Device await < 1 ms (Heuristik) 1–5 ms (Heuristik) > 5 ms anhaltend (Heuristik) Save-Verzögerung, verzögerte Inventar-/Loot-Interaktion, Stottern
Device %util < 50 % (Heuristik) 50–85 % (Heuristik) > 85 % anhaltend (Heuristik) Queueing, lange Disk-Waits, Stalls bei Save-Bursts
CPU iowait < 2 % (Heuristik) 2–10 % (Heuristik) > 10 % (Heuristik) Pausen und Rubber-Banding, weil CPU auf Storage wartet
Save-Burst-Dauer < 2 s (Heuristik) 2–5 s (Heuristik) > 5 s (Heuristik) Rubber-Banding während Autosaves; lange Bursts überdauern UI-Latenz

Auswertungslogik (Heuristik, EN-Storage-Guide):

  • await immer mit %util, Queue-Tiefe und Durchsatz lesen; ein schnelles Gerät kann beschäftigt aussehen, ein langsames Bursts zeigen.
  • Hoher iowait + hoher await = stärkerer Storage-Verdacht als jeder Einzelwert. Beide gesund → JVM/GC, Zombie-Dichte, Netzwerk prüfen.
  • Save-Bursts im selben Intervall messen, in dem Spieler Lag melden; wiederholbare Muster schlagen Einzelspitzen.
  • Mehrere Sessions vergleichen; ein einzelner Ausschlag kann ein konkurrierender Prozess auf demselben Gerät sein.

4. Mess-Befehle

Alle Befehle 1:1 aus dem EN-Storage-Guide. Werkzeuge stammen aus dem Paket sysstat (Debian/Ubuntu: apt install sysstat).

Befehl Zweck
iostat -x 2 Gerät-Latenz, %util, Queue-Tiefe, Durchsatz alle 2 Sekunden
pidstat -d -p $(pgrep -fi zomboid) 2 Disk-Aktivität des Java-/Launcher-Prozesses
vmstat 2 wa (iowait), Run-Queue, Swap-Druck, Speicher
pidstat -t 2 Threads — der heiße Simulationskern
df -h ${PZ_DATA_DIR}/Saves/Multiplayer Filesystem der Live-Save-Struktur; bei tmpfs: tmpfs-Mount
du -sh ${PZ_DATA_DIR}/Saves/Multiplayer/<world> Weltengröße vor tmpfs-Dimensionierung
findmnt -T ${PZ_DATA_DIR}/Saves/Multiplayer Mount-Quelle und Optionen für den Save-Pfad
rsync -an --delete -- <tmpfs-world>/ <durable-mirror>/ Trockenlauf des Sync-Back (zeigt nur, was geändert würde)
systemctl list-timers 'pz-*' Prüft aktive tmpfs-Sync-Timer

Findet pgrep -fi zomboid mehrere Prozesse, die tatsächliche Java-PID direkt an pidstat -d -p PID 2 übergeben (Heuristik, EN-Storage-Guide).

5. Eskalationsleiter

Die folgende Reihenfolge übernimmt die Eskalationsstufen aus dem PDF- Handbuch Kapitel 2 und dem EN-Storage-Guide 1:1 (Heuristik). Pro Messzyklus immer nur eine Stufe anwenden.

  1. Platzierung verifizieren: Liegen Welt, Java-Prozess und Swap auf dem vorgesehenen Gerät? (Repo-Pfad: ${PZ_DATA_DIR} = /opt/pzserver/Zomboid, Repo-Default.)
  2. Beweise zeitlich zuordnen: Lag-Reports mit Save-Burst-Zeitpunkten (SaveWorldEveryMinutes=15, Repo-Default), Connect-Versuchen und Besuchen lang ungesehener Zellen korrelieren.
  3. Konkurrenz reduzieren: Backups, Paket-Caches und Bulk-Jobs vom Save-Gerät weg oder außerhalb der Peak-Zeiten legen. Das Repo-Backup läuft um 04:00 (zomboid-backup.timer, Persistent, Repo-Default); wer nachts spielt, verschiebt den Zeitpunkt.
  4. Storage eskalieren: Welt auf NVMe ziehen; tmpfs erst nach den Stufen 1–3.
  5. Gameplay/Compute eskalieren: Sind Latenzen gesund, Zombie-Dichte, Population, JVM, CPU und Netzwerk prüfen.

Mini-Check vor jeder Eskalation

Vor dem ersten Hebel folgende Befehle laufen lassen (Heuristik, EN- Storage-Guide; Repo-Pfad-Defaults):

df -h ${PZ_DATA_DIR}/Saves/Multiplayer
du -sh ${PZ_DATA_DIR}/Saves/Multiplayer/<world>
iostat -x 2 | tee /tmp/iostat-pre.log
# danach Last auslösen (z. B. Spieler betritt neue Zelle),
# iostat beobachten und Log mit "iostat-pre.log" vergleichen.

So lässt sich später objektiv zeigen, ob die Eskalationsstufe tatsächlich geholfen hat — sonst bleibt „gefühlt besser" als einziger Beleg.

6. tmpfs / RAM-Disk (Option außerhalb des Repo-Stands)

Wichtig (Repo-Stand): Das Repo liefert kein tmpfs-Setup. Alles in diesem Abschnitt ist ein optionaler Ausbau auf Basis des EN-Storage- Guides (Standard-Linux-tmpfs+rsync, keine TIS-Empfehlung; Heuristik). Wer den Standard-Repo-Pfad nicht verlassen will, überspringt diesen Abschnitt und bleibt auf dauerhaftem Storage unter ${PZ_DATA_DIR} (Repo-Default).

6.1 Strategie und Reichweite

  • Live-Weltbaum auf tmpfs legen — der Pfad ${PZ_DATA_DIR}/Saves/Multiplayer (Repo-Default) ist das primäre Backup-Ziel, also auch der erste tmpfs-Kandidat.
  • Installation auf dauerhafter Platte lassen — Binaries und Java-Runtime sind read-mostly und werden ohnehin vom Linux-Page-Cache bedient.
  • Optional auch ${PZ_DATA_DIR}/Saves komplett, falls der größere Footprint gerechtfertigt ist — Pfad-Muster analog (Heuristik).

6.2 Größenplanung

Aktuelle Größe messen (Heuristik):

du -sh ${PZ_DATA_DIR}/Saves/Multiplayer

Faustregel: aktuelle Größe × 1,5 (Heuristik, EN-Storage-Guide). Niemals tmpfs größer wählen als: physisches RAM - JVM-Heap - 8 GB OS-Reserve - Sicherheitsmarge für andere Dienste (Heuristik, EN-Storage-Guide). Auf einem 24-GB-Host mit 12G Heap bleibt für tmpfs entsprechend wenig Luft — die Heap-Tier-Rechnung aus Hardware-Empfehlungen ist vorrangig.

6.3 fstab und Ownership

Repo-Pfade übernehmen (Heuristik, abweichend vom EN-Standardbeispiel):

# Beispiel: tmpfs auf /opt/pzserver/Zomboid/Saves/Multiplayer
# Pfad 1:1 aus .env.example: PZ_DATA_DIR=/opt/pzserver/Zomboid
# uid/gid des Server-Kontos einsetzen (default: pzserver)
tmpfs /opt/pzserver/Zomboid/Saves/Multiplayer tmpfs rw,nosuid,noexec,size=20G,uid=<UID>,gid=<GID>,mode=0750 0 0

UID/GID des Server-Kontos prüfen: id pzserver (Heuristik). uid=<UID> muss numerisch sein — Namen werden vom Mount-Helper nicht aufgelöst (EN-Storage-Guide).

6.4 Vorbereitung und Seed

Vor dem ersten Mount (Heuristik, EN-Storage-Guide):

sudo systemctl stop zomboid
sudo install -d -o pzserver -g pzserver /opt/pzserver/Zomboid/Saves/Multiplayer
# Dauerhafter Spiegel — Repo-Stand kennt diesen Pfad NICHT,
# eigene Konvention auserhalb des Repos:
sudo install -d -o pzserver -g pzserver /opt/pzserver-backup/Saves/Multiplayer
rsync -a --delete /opt/pzserver/Zomboid/Saves/Multiplayer/ /opt/pzserver-backup/Saves/Multiplayer/
sudo systemctl daemon-reload
sudo mount /opt/pzserver/Zomboid/Saves/Multiplayer

Ohne Seed ist das tmpfs beim ersten Boot leer — der Server startet ohne Welt (Heuristik, EN-Storage-Guide).

6.5 Boot-Seed-Service (außerhalb Repo-Stand)

# /etc/systemd/system/pz-ramdisk-seed.service
[Unit]
Description=Seed Project Zomboid multiplayer saves from durable storage
Wants=local-fs.target
After=local-fs.target
RequiresMountsFor=/opt/pzserver/Zomboid/Saves/Multiplayer

[Service]
Type=oneshot
User=pzserver
Group=pzserver
TimeoutStartSec=30min
ExecStart=/usr/bin/rsync -a --delete -- /opt/pzserver-backup/Saves/Multiplayer/ /opt/pzserver/Zomboid/Saves/Multiplayer/

[Install]
WantedBy=multi-user.target

Liegt außerhalb des Repo-Stands (Heuristik, EN-Storage-Guide): Repo liefert keine eigene Service-Datei; die obigen Units entstehen manuell in /etc/systemd/system/.

6.6 Sync-Back-Timer (außerhalb Repo-Stand)

Der Sync-Back-Timer im EN-Storage-Guide läuft alle 5 Minuten; das ist eine administrative Wahl, kein TIS-Intervall. Mit Persistent=true auf dem Timer kann ein Catch-up-Lauf beim Boot den rsync---delete gegen ein leeres tmpfs feuern und den dauerhaften Spiegel leeren — das Requires/ After=pz-ramdisk-seed.service im Service schützt daraus nur, wenn der Timer regulär zieht (Heuristik, EN-Storage-Guide).

# /etc/systemd/system/pz-ramdisk-sync.timer
[Unit]
Description=Periodically back up the Project Zomboid tmpfs world

[Timer]
OnCalendar=*-*-* *:0/5:00
Persistent=true
RandomizedDelaySec=30s
Unit=pz-ramdisk-sync.service

[Install]
WantedBy=timers.target

6.7 ExecStop-rsync im Server-Wrapper (außerhalb Repo-Stand)

Der Repo-zomboid.service enthält keinen ExecStop-rsync (Repo-Stand, 1:1 aus systemd/zomboid.service). Wer tmpfs nutzt, ergänzt den Service um eine ExecStop=--Zeile, damit ein sauberer Stop die Welt noch synchronisiert, bevor der Prozess endet:

# /etc/systemd/system/zomboid.service (Erweiterung)
[Service]
ExecStop=/usr/bin/rsync -a --delete -- /opt/pzserver/Zomboid/Saves/Multiplayer/ /opt/pzserver-backup/Saves/Multiplayer/

ProtectSystem=strict und andere Sandboxing-Direktiven nicht ohne Test hinzufügen — sie können den tmpfs-Pfad oder den Spiegel-Pfad unerwartet abschneiden (Heuristik, EN-Storage-Guide).

Hinweis (Community-Quelle: pzwiki): Die Entwickler raten von direkter systemd-Invocation wegen der SIGTERM-Behandlung ab; das Repo startet trotzdem per systemd mit sauberem /quit-Pfad über die Stop-Skripte — siehe systemd-Referenz.

6.8 Risiko-Kasten

  • Eine RAM-Disk ist kein Backup (Heuristik, EN-Storage-Guide).
  • Kernel-Panic, Host-Crash oder Stromausfall verlieren alles seit dem letzten erfolgreichen Sync; ExecStop-rsync läuft nach plötzlichem Stromausfall nicht.
  • Backup-Ziel darf nie auf dem tmpfs selbst liegen — der Spiegel auf dauerhaftem Storage ist nur eine Arbeitskopie, keine Historie.
  • Timer- und ExecStop-rsyncs können den Weltbaum mitten im Save erwischen; im Zweifel das letzte Backup bevorzugen, nicht den Spiegel (Heuristik, EN-Storage-Guide).
  • Restore testen: Server stoppen, Live-Kopie zur Seite legen, aus Backup zurückladen, tmpfs neu seeden, Welt laden — erst dann in Produktion vertrauen.
  • Wenn der Sync-Service ausfällt, bleibt Storage flüchtig; eine spätere erfolgreiche Sync kopiert den aktuellen tmpfs-Inhalt — sie rekonstruiert bereits verlorene Daten nicht (Heuristik).

6.9 Wann tmpfs NICHT passt

  • Host hat nicht genug RAM für JVM-Heap, Live-Saves und OS-Reserve.
  • Kleiner Host mit Multi-GB-Welten — Kapazitätslimit und Java-Speicher konkurrieren.
  • Erst NVMe evaluieren; tmpfs nur bei großer RAM-Reserve als zusätzliches Experiment (Heuristik, EN-Storage-Guide).

7. Respawn-Interaktion mit Storage

Die drei Sandbox-Werte Respawn Hours, Respawn Unseen Hours und Respawn Multiplier (pzwiki-Sandbox, dokumentiert im EN-Storage-Guide Kapitel 4) steuern, wann und wie viel Zombie-Respawn stattfindet. Wichtig (Community-Quelle, EN-Storage-Guide): Die exakte camelCase- Lua-Schreibweise ist nicht zweifelsfrei verifiziert — über das In-Game-Sandbox-UI oder den servertest_SandboxVars.lua-Editor setzen, nicht durch geratene Key-Namen. Das Repo-Preset coop-balanced.lua setzt RespawnHours=0 (Repo-Default; aus = kein Respawn = keine Respawn- Berechnung, siehe Server-Konfiguration).

Wenn Spieler in lang ungesehene Gebiete vorstoßen, lädt der Server Population, Loot, Container und Fahrzeug-Zustand aus dem Storage — ein Read-/Write-Burst folgt. Bei hoher Storage-Latenz wird das als Loot-Lag, Inventory-Delay oder Loading-Delay spürbar (Heuristik, EN-Storage-Guide).

8. Migration-Hazard B41 → B42

Beim Host-Wechsel von B41 auf B42 kann beim Start Assertion Failed: Illegal termination of worker thread auftreten (Community-Quelle: pzwiki). Reparatur (Community-Quelle: pzwiki):

  1. steam_appid.txt mit Inhalt 108600 im Server-Verzeichnis anlegen.
  2. Alle Serverprozesse sauber stoppen.
  3. .ini, .lua, Zomboid- und Save-Verzeichnisse sichern.
  4. Bestehenden Zomboid-Ordner entfernen, damit B42 ihn neu erzeugen kann.
  5. Nur als kompatibel bekannte Konfiguration und Welt zurückladen.
  6. Ohne B42-Beta-Flag starten und ersten Save-Zyklus beobachten.

Details: Troubleshooting. Den Save-Baum nicht ohne verifiziertes Backup löschen.

9. Zusammenfassung

  • HDD-Symptome sind real, aber kein TIS-Muss — sie stammen aus Vendor- Beobachtungen (Community-Quelle).
  • NVMe ist der empfohlene Tier, gemessen am Gerät unter ${PZ_DATA_DIR}/Saves/Multiplayer (Heuristik).
  • tmpfs ist ein Repo-externes Experiment für Hosts mit großer RAM-Reserve (Heuristik); ohne Backup ist es wertlos.
  • Immer nur eine Schraube gleichzeitig drehen; Korrelation zwischen Lag- Report und Save-Zeitpunkt ist Pflicht (Heuristik).

Weiter: Performance-Guide · Hardware-Empfehlungen · Backup-und-Restore · Troubleshooting

Vertieft in Repo: pz-b42-server-guides/b42-storage-map-streaming-guide.md und docs/09-performance.md.

Clone this wiki locally