11 Speicher-Engines in MongoDB

Die Speicher-Engine ist das Herzstück einer Datenbank – die Schicht, die bestimmt, wie Daten physisch gespeichert, gelesen und modifiziert werden. Sie ist transparent für die Anwendung, die über die MongoDB-API interagiert, aber fundamental für Performance, Speichereffizienz und Funktionsumfang. MongoDB’s architektonische Stärke liegt darin, dass die Speicher-Engine austauschbar ist. Dieselbe Datenbank-API kann mit verschiedenen Storage Engines arbeiten, jede optimiert für spezifische Anforderungen.

Diese Modularität ist nicht akademisch, sondern praktisch relevant. Die Wahl der Storage Engine beeinflusst, wie viel RAM die Datenbank benötigt, wie stark Daten komprimiert werden, ob ACID-Transaktionen möglich sind und wie gut die Datenbank bei vielen parallelen Operationen skaliert. In der Praxis ist die Entscheidung allerdings meist einfach: WiredTiger ist seit MongoDB 3.2 der Standard und für nahezu alle Anwendungsfälle die richtige Wahl. Trotzdem lohnt sich ein Verständnis der Alternativen und der historischen Entwicklung.

11.1 Die Evolution: Von MMAPv1 zu WiredTiger

MongoDB startete 2009 mit MMAPv1 als einziger Storage Engine. Der Name kommt von “Memory-Mapped Files” – der Technik, Dateien direkt in den virtuellen Adressraum eines Prozesses zu mappen. Das Betriebssystem managed das Paging zwischen RAM und Disk, die Datenbank arbeitet, als wäre alles im Speicher. Dieser Ansatz ist einfach zu implementieren und nutzt das OS-Caching elegant.

MMAPv1 hatte aber fundamentale Limitierungen. Updates erfolgten in-place, was bei variablen Dokumentgrößen zu Fragmentierung führte. Ein Dokument, das wächst, muss verschoben werden, hinterlässt Lücken. Über Zeit fragmentiert die Datenbank, Speicher wird verschwendet. Das Concurrency-Modell war restriktiv – Database-Level-Locking in frühen Versionen, später Collection-Level, aber nie besser. Hohe parallele Last führte zu Contention und Wartezeiten.

2014 akquirierte MongoDB Inc. die Firma WiredTiger und integrierte deren gleichnamige Storage Engine. WiredTiger war von Anfang an für moderne Hardware und Workloads designed. Es nutzt MVCC (Multi-Version Concurrency Control), ähnlich PostgreSQL oder Oracle, was deutlich bessere Parallelität ermöglicht. Daten werden komprimiert gespeichert – typischerweise auf 30-50% der unkomprimierten Größe. Die Architektur unterstützt ACID-Transaktionen über mehrere Dokumente, was mit MMAPv1 unmöglich war.

Ab MongoDB 3.2 wurde WiredTiger zum Standard. MongoDB 4.0 entfernte MMAPv1 vollständig – ein klarer Schnitt, der signalisierte, dass WiredTiger nicht nur eine Option, sondern die Zukunft ist. Für neue Installationen gibt es keinen Grund, etwas anderes zu verwenden.

11.2 WiredTiger: Die moderne Standard-Engine

WiredTiger ist weit mehr als nur eine Speicher-Engine – es ist ein ausgereiftes Datenbanksystem in sich. Die Architektur basiert auf mehreren Schlüsselkonzepten, die zusammen außergewöhnliche Performance und Effizienz ermöglichen.

Das Concurrency-Modell nutzt MVCC, was bedeutet, dass Leser und Schreiber sich nicht blockieren. Wenn eine Transaktion ein Dokument liest, sieht sie eine konsistente Snapshot-Ansicht der Daten zum Zeitpunkt des Transaktionsstarts. Parallel können andere Transaktionen schreiben, ohne die lesende Transaktion zu beeinflussen. Dies ist fundamental anders als Lock-basierte Systeme wie MMAPv1, wo Schreiber alle Leser blockieren.

Technisch erreicht WiredTiger dies durch Versionierung. Jede Änderung erzeugt eine neue Version der Daten, alte Versionen bleiben temporär erhalten. Leser greifen auf die passende Version für ihren Snapshot zu. Ein Background-Thread (Eviction) räumt alte Versionen auf, sobald keine Transaktion sie mehr benötigt. Dieser Mechanismus kostet Speicher – typischerweise 10-20% Overhead – aber der Performance-Gewinn ist dramatisch.

Die Datenkompression ist ein weiteres Highlight. WiredTiger unterstützt mehrere Algorithmen: Snappy (Standard), Zlib und Zstandard. Snappy ist schnell, Zlib komprimiert stärker aber langsamer, Zstandard bietet das beste Verhältnis von Kompression zu Speed. Die Wahl hängt vom Use-Case ab. Für typische Dokumente erreicht Snappy 2-3x Kompression – eine 1 GB Datenbank benötigt nur 300-500 MB auf Disk. Dies spart nicht nur Speicher, sondern auch I/O – weniger Daten müssen zwischen Disk und RAM transferiert werden.

Die Speicherung basiert auf B+ Trees – eine bewährte Datenstruktur, die effizientes Suchen, Einfügen und sequentielles Scannen ermöglicht. Dokumente werden in Seiten (Pages) organisiert, typischerweise 4-32 KB groß. Diese Seiten werden komprimiert gespeichert, dekomprimiert beim Lesen. Indizes nutzen ebenfalls B+ Trees, was konsistente Performance über verschiedene Operationen garantiert.

Das Journal ist WiredTigers Mechanismus für Durability. Jede Schreiboperation wird zunächst ins Journal geschrieben – ein Write-Ahead-Log auf Disk. Erst danach gilt die Operation als committed. Periodisch (Standard: alle 60 Sekunden) schreibt WiredTiger einen Checkpoint – einen konsistenten Snapshot aller Daten auf Disk. Im Crash-Fall startet MongoDB vom letzten Checkpoint und replayed das Journal, um alle commits seit dem Checkpoint wiederherzustellen.

Die Cache-Größe ist ein kritischer Tuning-Parameter. WiredTiger allokiert standardmäßig 50% des RAM minus 1 GB oder 256 MB, je nachdem was größer ist. Auf einem Server mit 16 GB RAM wären das 7 GB Cache. Dieser Cache ist WiredTigers Working Set – die Daten, auf die häufig zugegriffen wird. Je mehr davon im Cache passt, desto weniger Disk I/O ist nötig. Für optimale Performance sollte das Working Set komplett in den Cache passen.

Merkmal Beschreibung Vorteil Konfiguration
MVCC Multi-Version Concurrency Control Leser blockieren Schreiber nicht Automatisch
Kompression Snappy/Zlib/Zstandard 2-3x Speicherreduktion storage.wiredTiger.collectionConfig.blockCompressor
B+ Trees Ausgeglichene Baum-Struktur Konsistente O(log n) Performance Automatisch
Journaling Write-Ahead-Log Crash-Recovery storage.journal.enabled
Cache In-Memory Working Set Minimiert Disk I/O storage.wiredTiger.engineConfig.cacheSizeGB
Checkpoints Periodische Disk-Snapshots Persistenz ohne ständiges Flushing Alle 60s automatisch

11.3 In-Memory Storage Engine: Geschwindigkeit ohne Persistenz

Die In-Memory Engine ist eine Spezialvariante, die ausschließlich im RAM operiert. Daten werden nie auf Disk geschrieben, außer für Replikation-Logs in Replica Sets. Dies eliminiert I/O komplett und erreicht Sub-Millisekunden-Latenz für praktisch alle Operationen.

Der Use-Case ist spezialisiert: Caching, Session-Stores, Echtzeit-Analytics auf flüchtigen Daten. Überall, wo extreme Geschwindigkeit wichtiger ist als Persistenz. Ein typisches Szenario wäre ein Multiplayer-Game-Backend, das Spielerzustände für aktive Sessions hält. Diese Daten müssen blitzschnell verfügbar sein, aber wenn der Server crasht, können Spieler einfach reconnecten.

Die In-Memory Engine nutzt viele Konzepte von WiredTiger – MVCC, B+ Trees – aber ohne Journal und Checkpoints. Der gesamte Dataset muss in den konfigurierten RAM passen. Wächst er darüber hinaus, schlägt MongoDB fehl. Dies erfordert sorgfältiges Capacity Planning. TTL-Indizes sind hier besonders wertvoll, um alte Daten automatisch zu entfernen.

Ein wichtiger Punkt: Auch die In-Memory Engine schreibt Oplog-Einträge auf Disk, wenn Teil eines Replica Sets. Dies ermöglicht Replikation zu anderen Knoten. Ein Replica Set könnte einen In-Memory Primary für Geschwindigkeit haben und WiredTiger Secondaries für Persistenz – eine hybride Architektur für spezielle Anforderungen.

Die Konfiguration erfolgt über die mongod.conf:

storage:
  engine: inMemory
  inMemory:
    engineConfig:
      inMemorySizeGB: 10

Dies allokiert 10 GB für den Dataset. MongoDB startet nicht, wenn weniger RAM verfügbar ist.

11.4 Drittanbieter-Engines: Nischenexistenzen

Neben den offiziellen Engines existieren Drittanbieter-Varianten. TokuMX/TokuMXse nutzte Fractal Tree Indexing statt B+ Trees – eine Datenstruktur, die Schreiboperationen puffert und batch-wise verarbeitet. Dies führte zu besserer Schreib-Performance und höherer Kompression als MMAPv1, war aber nie offiziell unterstützt und ist heute obsolet.

RocksDB, entwickelt von Facebook, ist eine Key-Value-Engine basierend auf Log-Structured Merge Trees (LSM). Diese Architektur ist ideal für schreibintensive Workloads – inserts und updates sind extrem schnell. Der Trade-off: Reads sind langsamer, weil mehrere “Levels” durchsucht werden müssen. MongoDB-Varianten mit RocksDB existieren (hauptsächlich in Percona Server for MongoDB), aber für Standard-Workloads bietet WiredTiger meist bessere Balance.

Diese Engines sind heute primär historisch interessant. WiredTiger hat sich als so robust und performant erwiesen, dass spezialisiertere Engines kaum noch Nischen finden. Für die allermeisten Anwendungen ist die Frage nicht “welche Engine?”, sondern “wie tunen wir WiredTiger?”.

11.5 Praktische Aspekte: Abfragen und Wechseln

Die aktuelle Storage Engine lässt sich einfach abfragen:

db.serverStatus().storageEngine

Dies gibt ein Objekt zurück mit Name, Fähigkeiten und Status:

{
  "name": "wiredTiger",
  "supportsCommittedReads": true,
  "supportsSnapshotReadConcern": true,
  "readOnly": false,
  "persistent": true
}

Der Wechsel der Storage Engine ist nicht trivial, weil verschiedene Engines inkompatible Datenformate verwenden. Ein MMAPv1-Dataset kann nicht direkt von WiredTiger gelesen werden. Der Prozess erfordert Export und Reimport:

# 1. Daten exportieren (mit alter Engine laufend)
mongodump --out=/backup

# 2. MongoDB stoppen
sudo systemctl stop mongod

# 3. Altes Datenverzeichnis sichern
sudo mv /var/lib/mongodb /var/lib/mongodb.mmap

# 4. Neues Verzeichnis erstellen
sudo mkdir /var/lib/mongodb
sudo chown mongodb:mongodb /var/lib/mongodb

# 5. Engine in mongod.conf ändern
# storage:
#   engine: wiredTiger

# 6. MongoDB mit neuer Engine starten
sudo systemctl start mongod

# 7. Daten importieren
mongorestore /backup

Dieser Prozess ist zeitaufwendig für große Datasets – Stunden oder Tage bei Terabytes. In Replica Sets ist es eleganter: Ein Secondary wird mit neuer Engine aufgesetzt, repliziert Daten, wird zum Primary promoted, dann werden die anderen Knoten migriert. Dies vermeidet Downtime.

Für neue Deployments stellt sich die Frage nicht – WiredTiger ist voreingestellt und muss nicht konfiguriert werden. Nur für sehr spezielle Anforderungen (In-Memory für Caching) oder bei Migration alter MMAPv1-Systeme wird man mit Storage-Engine-Konfiguration konfrontiert.

11.6 Tuning für optimale Performance

WiredTiger ist out-of-the-box performant, aber Tuning kann signifikante Verbesserungen bringen. Die wichtigsten Parameter:

Die Cache-Größe sollte zum Workload passen. Der Standard (50% RAM minus 1 GB) ist konservativ. Auf dedizierten Datenbank-Servern kann 70-80% des RAMs sinnvoll sein. Wichtig: Genug RAM für OS-Caches lassen – WiredTiger ist nicht der einzige RAM-Konsument.

Die Kompression sollte gewählt werden basierend auf CPU vs. Disk. Snappy (Standard) ist CPU-freundlich und ausreichend schnell. Auf Systemen mit langsamer Disk aber starker CPU kann Zlib oder Zstandard sinnvoll sein – stärkere Kompression reduziert I/O auf Kosten von CPU. Auf Systemen mit schneller NVMe SSD aber schwacher CPU könnte man Kompression ganz deaktivieren.

Journaling kann für extreme Performance-Anforderungen adjustiert werden. Der Standard committed alle 100ms aufs Journal. Dies auf 300ms zu erhöhen reduziert I/O, erhöht aber potentiellen Datenverlust bei Crash. Für unkritische Daten könnte man Journal ganz deaktivieren – dramatischer Performance-Boost, aber keinerlei Crash-Recovery.

Diese Tunings sollten vorsichtig vorgenommen und gründlich getestet werden. Defaults existieren aus gutem Grund – sie funktionieren für die meisten Fälle. Abweichungen sollten durch Messungen gerechtfertigt sein, nicht durch Vermutungen.

Die Wahl und Konfiguration der Storage Engine ist fundamental für MongoDB’s Verhalten, aber in der Praxis meist unkompliziert. WiredTiger ist ausgereift, performant und für nahezu alle Workloads geeignet. Die Zeiten, in denen man zwischen mehreren gleichwertigen Optionen wählen musste, sind vorbei – WiredTiger hat gewonnen, und das ist gut so.