25 Shutdown von MongoDB: Sauber beenden statt hart killen

Das Herunterfahren einer MongoDB-Instanz scheint trivial – einfach den Prozess stoppen, fertig. Aber MongoDB ist eine Datenbank, die kontinuierlich mit Daten arbeitet, Writes buffert, Journals schreibt und Caches managed. Ein unsauberer Shutdown kann zu Dateninkonsistenzen, langen Recovery-Zeiten beim nächsten Start oder im schlimmsten Fall zu Datenkorruption führen. Die Art und Weise, wie MongoDB beendet wird, ist deshalb nicht belanglos.

Ein graceful Shutdown gibt MongoDB Zeit, alle gepufferten Writes zu flushen, das Journal zu synchronisieren und Metadaten sauber zu schließen. Ein forceful Shutdown – etwa durch kill -9 oder Stromausfall – unterbricht diese Prozesse mitten in der Arbeit. MongoDB ist robust genug, um nach einem Hard-Crash zu recovern, aber dieser Recovery kostet Zeit und ist nicht garantiert fehlerfrei. Für produktive Systeme sollten Shutdowns immer geplant und sauber durchgeführt werden.

25.1 Was beim Shutdown intern passiert

Bevor wir die praktischen Methoden durchgehen, lohnt es sich zu verstehen, was MongoDB beim Shutdown macht. Dieses Verständnis erklärt, warum manche Methoden besser sind als andere und was schiefgehen kann.

Wenn MongoDB ein Shutdown-Signal empfängt (etwa SIGTERM oder SIGINT), startet es einen geordneten Herunterfahren-Prozess. Zuerst stoppt es die Annahme neuer Client-Verbindungen. Der Server akzeptiert keine neuen Queries mehr, aber bestehende Verbindungen bleiben aktiv, um laufende Operationen zu beenden.

Dann wartet MongoDB auf den Abschluss aller laufenden Operationen. Reads und Writes, die bereits begonnen haben, werden zu Ende geführt. Dies kann Sekunden dauern bei einfachen Queries oder Minuten bei komplexen Aggregations-Pipelines oder großen Bulk-Writes. Neue Operationen werden mit einer “server is shutting down”-Meldung abgelehnt.

Parallel dazu flusht die WiredTiger Storage Engine alle gepufferten Daten zu Disk. Der Write-Ahead-Log (Journal) wird synchronisiert, um sicherzustellen, dass alle committed Writes persistent sind. Ein finaler Checkpoint wird geschrieben – ein konsistenter Snapshot der gesamten Datenbank zum Zeitpunkt des Shutdowns. Dieser Checkpoint ist kritisch: Beim nächsten Start kann MongoDB von diesem Punkt fortsetzen, statt das gesamte Journal zu replayan.

Schließlich schließt MongoDB alle offenen Dateien sauber, updated Lock-Files und terminiert. Der gesamte Prozess ist designed, um einen konsistenten Zustand zu hinterlassen. Wenn der nächste Start erfolgt, findet MongoDB eine saubere Datenbank vor und startet sofort, ohne Recovery-Schritte.

Bei einem forceful Shutdown – etwa durch kill -9 oder Stromausfall – werden diese Schritte übersprungen. Gepufferte Daten sind möglicherweise nicht zu Disk geschrieben. Der Journal ist inkonsistent. Beim nächsten Start muss MongoDB das Journal replayan, um einen konsistenten Zustand wiederherzustellen. Dies kann bei großen Datenbanken oder langen Journals Minuten oder Stunden dauern. In seltenen Fällen, besonders bei Filesystem-Korruption durch den Crash, kann Recovery fehlschlagen.

25.2 Die drei Methoden: Shell, systemd und Signale

MongoDB bietet mehrere Wege für einen Shutdown, mit unterschiedlichen Eigenschaften und Use-Cases.

25.2.1 Methode 1: Administrative Shutdown über die Shell

Die sauberste Methode ist der administrative Shutdown über mongosh. Wir verbinden uns mit der MongoDB-Instanz und senden ein Shutdown-Command:

mongosh --port 27017

In der Shell:

use admin
db.shutdownServer()

Oder kompakter:

db.adminCommand({ shutdown: 1 })

Dieses Command erfordert Rechte auf der admin-Datenbank. Ohne Authentifizierung ist dies kein Problem. Mit aktivierter Authentifizierung muss man sich erst als Admin authentifizieren:

use admin
db.auth("admin", "SecurePassword123!")
db.shutdownServer()

Der Vorteil dieser Methode: Sie ist explizit und sauber. MongoDB empfängt das Command über den normalen Netzwerk-Kanal, verarbeitet es wie jede andere Operation und initiiert den graceful Shutdown. Die Shell-Verbindung wird getrennt, sobald MongoDB herunterfährt. Der Exit-Code ist 0 (sauberer Exit).

Der Nachteil: Es erfordert eine funktionierende Netzwerk-Verbindung und Authentifizierung. Wenn das Netzwerk gestört ist oder man die Admin-Credentials nicht hat, funktioniert diese Methode nicht. Für automatisierte Shutdowns in Scripts ist das Credential-Management knifflig.

25.2.2 Methode 2: systemd Service Management

Auf modernen Linux-Systemen läuft MongoDB typischerweise als systemd-Service. Der Shutdown über systemd ist die idiomatische Methode für Service-Management:

sudo systemctl stop mongod

systemd sendet ein SIGTERM-Signal an den mongod-Prozess. MongoDB empfängt dies und initiiert den graceful Shutdown, wie oben beschrieben. systemd wartet eine konfigurierbare Zeitspanne (typischerweise 90 Sekunden) auf den Exit. Terminiert MongoDB nicht innerhalb dieser Frist, sendet systemd ein SIGKILL, das den Prozess forceful beendet.

Diese Timeout-Konfiguration ist in der systemd-Unit-Datei /lib/systemd/system/mongod.service:

[Service]
Type=forking
TimeoutStartSec=180
TimeoutStopSec=180

Der TimeoutStopSec-Wert von 180 Sekunden gibt MongoDB 3 Minuten Zeit für einen sauberen Shutdown. Für sehr große Datenbanken mit viel zu flushendem Cache könnte dies zu kurz sein. Man kann es anpassen:

sudo systemctl edit mongod

Und überschreiben:

[Service]
TimeoutStopSec=600

Dies gibt MongoDB 10 Minuten. Nach dem Edit:

sudo systemctl daemon-reload

Der Vorteil von systemd-Shutdown: Es funktioniert ohne Netzwerk oder Credentials. Es ist die Standard-Methode für Service-Management und integriert mit System-Monitoring. Automatisierte Restart-Policies und Dependency-Management sind möglich.

Der Nachteil: Man muss root- oder sudo-Rechte haben. Für non-root-User ist dies nicht direkt möglich. Und das forceful SIGKILL nach Timeout kann problematisch sein, wenn der Shutdown einfach lange dauert.

25.2.3 Methode 3: Manuelle Signale

Die Low-Level-Methode ist das direkte Senden von OS-Signalen an den mongod-Prozess. Zuerst finden wir die PID:

ps aux | grep mongod
# Oder spezifischer
pgrep mongod

Die Output zeigt die PID, etwa 12345. Wir senden ein SIGTERM (Signal 15) oder SIGINT (Signal 2):

kill -15 12345
# Oder
kill -TERM 12345
# Oder SIGINT
kill -2 12345
# Oder
kill -INT 12345

SIGTERM und SIGINT sind funktional äquivalent für MongoDB – beide initiieren einen graceful Shutdown. Die Konvention: SIGTERM für Service-Shutdown, SIGINT für interaktive Abbrüche (Ctrl+C). MongoDB behandelt beide identisch.

Das gefährliche Signal ist SIGKILL (Signal 9):

kill -9 12345
# Oder
kill -KILL 12345

SIGKILL terminiert den Prozess sofort, ohne Chance für Cleanup. MongoDB kann nicht auf dieses Signal reagieren – das OS tötet den Prozess direkt. Dies hinterlässt die Datenbank potenziell inkonsistent. SIGKILL sollte nur in Notfällen verwendet werden, wenn MongoDB nicht mehr reagiert und graceful Shutdown fehlschlägt.

Der Vorteil manueller Signale: Sie funktionieren immer, erfordern keine Netzwerk-Verbindung und keine speziellen Permissions (außer die Berechtigung, den Prozess zu beenden, typischerweise derselbe User). Für Debugging oder Notfälle ist dies manchmal die einzige Option.

Der Nachteil: Es ist Low-Level und fehleranfällig. Falsche PID zu killen kann andere Prozesse terminieren. Die Signal-Nummern zu verwechseln (SIGTERM vs. SIGKILL) kann katastrophal sein. Für normale Operationen sind die höheren Abstraktionen (Shell-Command oder systemd) sicherer.

25.3 Replica Set Shutdown: Reihenfolge ist wichtig

In einem Replica Set ist die Shutdown-Reihenfolge nicht kritisch für Datenintegrität, aber sie beeinflusst Downtime und Failover-Verhalten. Die Best Practice: Secondaries zuerst, Primary zuletzt.

Der Ablauf für ein geplantes Shutdown eines gesamten Replica Sets:

# 1. Secondaries herunterfahren
ssh secondary1.example.com "sudo systemctl stop mongod"
ssh secondary2.example.com "sudo systemctl stop mongod"

# 2. Primary herunterstufen (optional, für schnelleren Shutdown)
mongosh --host primary.example.com --eval "rs.stepDown()"

# 3. Primary (nun Secondary) herunterfahren
ssh primary.example.com "sudo systemctl stop mongod"

Der rs.stepDown()-Befehl zwingt den Primary, zurückzutreten und eine Election auszulösen. Aber mit den Secondaries bereits down wird keine Election erfolgreich sein – das Set wird ohne Primary enden. Dies ist okay für ein geplantes komplettes Shutdown.

Alternativ, wenn man den Primary nicht stepDown will, fährt man ihn einfach als letztes herunter. MongoDB erkennt den Verlust des Primary, die Secondaries versuchen eine Election, finden keine Mehrheit (weil sie auch herunterfahren) und das Set endet ohne Primary.

Für das Starten gilt die umgekehrte Reihenfolge: Primary (oder ehemaliger Primary) zuerst, dann Secondaries. Dies minimiert die Zeit ohne Primary und vermeidet unnötige Elections.

25.4 Sharded Cluster Shutdown: Die Reihenfolge zählt

Sharded Clusters sind komplexer. Die Komponenten – mongos, Shards, Config Servers – haben Abhängigkeiten. Die empfohlene Shutdown-Reihenfolge:

  1. mongos-Router zuerst: Stoppt Client-Verbindungen. Neue Queries können nicht mehr eingehen.
  2. Shards (als Replica Sets): Jeder Shard wird als Replica Set heruntergefahren, Secondaries zuerst, Primary zuletzt.
  3. Config Servers zuletzt: Die Metadaten-Server als letztes stoppen.
# 1. Alle mongos-Router stoppen
ssh router1.example.com "sudo systemctl stop mongos"
ssh router2.example.com "sudo systemctl stop mongos"

# 2. Jeden Shard herunterfahren (Replica Set Prozedur)
# Shard 1
ssh shard1-sec1.example.com "sudo systemctl stop mongod"
ssh shard1-sec2.example.com "sudo systemctl stop mongod"
ssh shard1-primary.example.com "sudo systemctl stop mongod"

# Shard 2
ssh shard2-sec1.example.com "sudo systemctl stop mongod"
ssh shard2-sec2.example.com "sudo systemctl stop mongod"
ssh shard2-primary.example.com "sudo systemctl stop mongod"

# 3. Config Servers herunterfahren (auch ein Replica Set)
ssh config1.example.com "sudo systemctl stop mongod"
ssh config2.example.com "sudo systemctl stop mongod"
ssh config3.example.com "sudo systemctl stop mongod"

Diese Reihenfolge ist nicht absolut notwendig für Datenintegrität – MongoDB ist designed, um beliebige Shutdown-Reihenfolgen zu tolerieren. Aber sie minimiert Warnings in Logs und macht den Prozess vorhersehbar.

Beim Hochfahren ist die Reihenfolge kritischer: Config Servers zuerst, dann Shards, dann mongos. mongos braucht funktionierende Config Servers beim Start, um Metadaten zu lesen. Shards können unabhängig starten, aber mongos kann sie nicht routen, bevor Config Servers verfügbar sind.

25.5 Recovery nach Hard-Crash: Was MongoDB repariert

Trotz aller Vorsicht passieren Hard-Crashes – Stromausfälle, Kernel-Panics, forceful Kills in Notfällen. MongoDB’s Recovery-Mechanismus ist robust, aber nicht magisch. Beim Start nach einem Crash prüft MongoDB den Zustand:

Sauberer Shutdown-Marker vorhanden: Wenn MongoDB einen sauberen Shutdown durchgeführt hat, schreibt es einen Marker in die Datenbank. Beim nächsten Start sieht es diesen Marker und weiß, dass alles konsistent ist. Der Start ist instant – Sekunden typischerweise.

Marker fehlt (Crash): MongoDB erkennt, dass der letzte Shutdown unsauber war. Es startet im Recovery-Modus. WiredTiger liest das Journal und replayed alle Operationen seit dem letzten Checkpoint. Dies bringt die Datenbank zu einem konsistenten Zustand.

Die Dauer des Recovery hängt von zwei Faktoren ab: Größe des Journals und Komplexität der Operationen. Ein Journal mit 1 GB Daten und einfachen Writes könnte in Sekunden replayed sein. Ein Journal mit 10 GB und komplexen Updates könnte Minuten brauchen. Für sehr große Datenbanken mit viel Write-Aktivität kann Recovery zu einem Problem werden.

Die Logs während Recovery zeigen Progress:

{"t":{"$date":"2024-01-15T10:00:00.000Z"},"s":"I","c":"STORAGE","id":22430,"ctx":"initandlisten","msg":"WiredTiger message","attr":{"message":"[1705315200:000000][12345:0x7f1234567890], txn-recover: Recovering log 3 through 5"}}
{"t":{"$date":"2024-01-15T10:00:05.000Z"},"s":"I","c":"STORAGE","id":22430,"ctx":"initandlisten","msg":"WiredTiger message","attr":{"message":"[1705315205:000000][12345:0x7f1234567890], txn-recover: recovery log replay complete, 10000 ops applied"}}

Diese Messages zeigen, wie viele Journal-Files replayed werden und wie viele Operationen. Bei langer Recovery (über 60 Sekunden) sollte man sich Sorgen machen und untersuchen, warum das Journal so groß ist oder warum Checkpoints selten sind.

In seltenen Fällen schlägt Recovery fehl. Typische Ursachen sind Filesystem-Korruption (das Journal oder Data-Files sind beschädigt) oder Out-of-Disk-Space während Recovery. Die Logs zeigen spezifische Fehler. Die Lösung ist oft, von einem Backup zu restoren – ein weiterer Grund, warum regelmäßige Backups nicht optional sind.

25.6 Best Practices: Shutdowns planen und automatisieren

Für produktive Systeme sollten Shutdowns niemals ad-hoc oder reaktiv sein. Geplante Shutdowns für Wartung, Upgrades oder Hardware-Wechsel sollten dokumentiert und getestet sein. Ein typischer Shutdown-Runbook könnte sein:

  1. Ankündigung: Warn-Phase für Anwendungen und Users. 30 Minuten vorher ein Maintenance-Mode-Flag setzen.
  2. Load-Reduzierung: Batch-Jobs stoppen, Background-Tasks pausieren, um Write-Load zu reduzieren.
  3. Backup-Verification: Sicherstellen, dass ein aktuelles Backup existiert, falls etwas schiefgeht.
  4. Shutdown-Execution: Nach dem oben beschriebenen Prozedere, mit Monitoring von Logs und Status.
  5. Post-Shutdown-Verification: Bestätigen, dass Prozesse cleanly terminiert haben, Disk-Space prüfen, Logs auf Errors checken.

Für automatisierte Shutdowns – etwa nächtliche Restarts für Memory-Cleanup in Dev-Umgebungen – sollte Scripting mit Error-Handling verwendet werden:

#!/bin/bash
# Safe MongoDB Shutdown Script

set -e

TIMEOUT=300  # 5 Minuten Maximum

echo "$(date): Initiating MongoDB shutdown..."

# Versuche graceful shutdown
if mongosh --quiet --eval "db.adminCommand({shutdown: 1})" > /dev/null 2>&1; then
    echo "$(date): Shutdown command sent successfully"
else
    echo "$(date): Shell shutdown failed, trying systemd..."
    sudo systemctl stop mongod
fi

# Warte auf Process-Ende
for i in $(seq 1 $TIMEOUT); do
    if ! pgrep mongod > /dev/null; then
        echo "$(date): MongoDB stopped successfully after $i seconds"
        exit 0
    fi
    sleep 1
done

# Timeout erreicht
echo "$(date): ERROR: MongoDB did not stop within $TIMEOUT seconds"
echo "$(date): Checking for hung operations..."
mongosh --quiet --eval "db.currentOp()" || true

exit 1

Dieses Script versucht zuerst den sauberen Shell-Shutdown, fällt auf systemd zurück, wartet mit Timeout und loggt Errors. Für Produktionssysteme sollte es erweitert werden mit Alerting, wenn Shutdown fehlschlägt.

Die folgende Tabelle fasst die Shutdown-Methoden zusammen:

Methode Signal Graceful Erfordert Use-Case
db.shutdownServer() - Ja Netzwerk, Auth Manuelle Admin-Shutdowns
systemctl stop SIGTERM Ja sudo Standard für Service-Management
kill -TERM / kill -INT SIGTERM/SIGINT Ja Process-Owner Debugging, Scripts
kill -9 SIGKILL Nein Process-Owner Nur in Notfällen!
Stromausfall - Nein - Ungewollt, Recovery nötig

MongoDB zu stoppen ist keine triviale Operation. Die Wahl zwischen graceful und forceful Shutdown kann den Unterschied bedeuten zwischen sofortigem Restart und minuten- oder stundenlanger Recovery. Für produktive Systeme sollten Shutdowns immer geplant, graceful und dokumentiert sein. SIGKILL und forceful Termination sind Notfall-Werkzeuge, keine Standard-Operationen. Mit Verständnis der internen Prozesse und Verwendung der richtigen Methoden bleibt die Datenbank konsistent und der nächste Start schnell.