Monotonic Clock vs. Wall Clock: Zeitmessung unter Linux richtig verstehen
AI generated
$
/etc
Linux · Zeitmessung · Kernel · Systemprogrammierung
Monotonic Clock vs. Wall Clock
zwei Uhren, die niemals verwechselt werden sollten

Der Linux-Kernel führt nicht eine, sondern mehrere Uhren gleichzeitig, und die Wahl der falschen Uhr für die falsche Aufgabe führt zu Bugs, die nur bei einer NTP-Korrektur oder einem manuellen Zeitsprung sichtbar werden. Dieser Leitfaden erklärt den Unterschied zwischen CLOCK_REALTIME und CLOCK_MONOTONIC, warum Timeouts und Retry-Logik die Wall Clock meiden sollten und wie Skripte robust gegen Zeitsprünge bleiben.

14 Min. Lesezeit CLOCK_MONOTONIC · CLOCK_REALTIME · clock_gettime Linux · Kernel · Bash · systemd

1. Zwei Uhren im Kernel: CLOCK_REALTIME und CLOCK_MONOTONIC

Der Linux-Kernel stellt Anwendungen nicht nur eine, sondern mehrere unterschiedliche Uhren zur Verfügung, jede mit einer eigenen Garantie und einem eigenen Einsatzzweck. CLOCK_REALTIME, gemeinhin als Wall Clock bezeichnet, liefert die tatsächliche Kalenderzeit, so wie sie ein Mensch von einer Uhr abliest, inklusive Datum und Uhrzeit. CLOCK_MONOTONIC, die Monotonic Clock, liefert dagegen keine Kalenderzeit, sondern lediglich einen fortlaufend steigenden Zählerwert seit einem beliebigen, nicht spezifizierten Startpunkt, meist dem Systemstart.

Der entscheidende Unterschied liegt in der Garantie: Die Wall Clock kann sich jederzeit ändern, vorwärts wie rückwärts, etwa durch eine NTP-Korrektur, eine manuelle Anpassung durch einen Administrator oder eine Zeitzonenänderung. Die Monotonic Clock dagegen garantiert per Definition, niemals rückwärts zu laufen, unabhängig davon, was mit der Systemzeit sonst passiert. Diese Garantie macht die Monotonic Clock zum einzig korrekten Werkzeug für alles, was Zeitdifferenzen oder Laufzeiten misst, während die Wall Clock ausschließlich für die Anzeige und Speicherung von Kalenderzeitpunkten zuständig bleibt.

In der Praxis vermischen viele Entwickler beide Konzepte, oft ohne es zu bemerken, weil date +%s und ähnliche Befehle standardmäßig die Wall Clock liefern. Wer damit Laufzeiten misst, baut ein Skript, das unter normalen Umständen korrekt funktioniert, aber genau dann fehlschlägt, wenn eine NTP-Korrektur während der Messung die Systemzeit verändert. Das Verständnis von Monotonic Clock vs. Wall Clock ist deshalb kein akademisches Detail, sondern eine praktische Voraussetzung für robuste Systemprogrammierung.

2. Warum sich die Wall Clock rückwärts bewegen kann

Ein frisch gestarteter Server hat oft eine ungenaue Systemzeit, bis der NTP-Client, etwa chrony oder systemd-timesyncd, die erste Synchronisation mit einem Zeitserver abgeschlossen hat. Diese erste Korrektur kann die Systemzeit um Sekunden oder sogar Minuten nach vorne oder nach hinten verschieben, abhängig davon, wie stark die interne Hardware-Uhr vom tatsächlichen Zeitpunkt abweicht. Ein Prozess, der genau während dieser Korrektur die Wall Clock zur Zeitmessung nutzt, sieht in seltenen Fällen eine Zeitdifferenz, die negativ ist, obwohl real Zeit vergangen ist.

Auch im laufenden Betrieb passiert das: chrony und ähnliche Dienste gleichen kleine Abweichungen normalerweise sanft aus, sogenanntes Slewing, bei dem die Uhr über einen längeren Zeitraum leicht schneller oder langsamer läuft, statt abrupt zu springen. Größere Abweichungen, etwa nach einer längeren Netzwerktrennung oder einem manuellen date -s-Befehl durch einen Administrator, werden dagegen oft als abrupter Sprung angewendet, sogenanntes Stepping. Genau dieser Sprung ist die Ursache, weshalb Wall Clock-basierte Zeitmessung in Produktionssystemen als fehleranfällig gilt.

3. Monotonic Clock in der Praxis: uptime und clock_gettime

Unter Linux lässt sich der monotone Zähler auf mehreren Ebenen beobachten. Die Datei /proc/uptime zeigt in der ersten Spalte die Sekunden seit dem Systemstart, direkt abgeleitet aus der internen Monotonic Clock des Kernels. Für präzisere Messungen in eigenen Programmen steht die POSIX-Funktion clock_gettime(CLOCK_MONOTONIC, &ts) zur Verfügung, die eine Struktur mit Sekunden und Nanosekunden seit dem nicht spezifizierten Referenzpunkt zurückgibt. Der Nanosekunden-Anteil macht diese Funktion auch für hochauflösende Performance-Messungen innerhalb einzelner Funktionsaufrufe geeignet.

Auf Kommandozeilenebene liefert date +%s.%N zwar Nanosekunden-Präzision, basiert aber weiterhin auf der Wall Clock und ist damit für reine Laufzeitmessungen ungeeignet. Für Shell-Skripte, die Laufzeiten korrekt messen wollen, bietet sich stattdessen ein direkter Blick in /proc/uptime an, kombiniert mit einer einfachen Differenzberechnung zwischen Start- und Endwert.


#!/usr/bin/env bash
# Comparing wall clock vs monotonic time for duration measurement
set -euo pipefail

# WRONG for duration measurement: wall clock can jump backward
start_wall="$(date +%s.%N)"
sleep 2
end_wall="$(date +%s.%N)"
echo "Wall clock delta: $(echo "$end_wall - $start_wall" | bc) seconds"

# RIGHT: monotonic counter from /proc/uptime, immune to NTP jumps
start_mono="$(awk '{print $1}' /proc/uptime)"
sleep 2
end_mono="$(awk '{print $1}' /proc/uptime)"
echo "Monotonic delta: $(echo "$end_mono - $start_mono" | bc) seconds"

# A small C program calling clock_gettime(CLOCK_MONOTONIC, ...) directly
cat > /tmp/mono_demo.c << 'EOF'
#include <stdio.h>
#include <time.h>
int main(void) {
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    printf("monotonic: %lld.%09ld\n", (long long)ts.tv_sec, ts.tv_nsec);
    return 0;
}
EOF
gcc -o /tmp/mono_demo /tmp/mono_demo.c && /tmp/mono_demo

4. Auswirkungen auf Timeouts und Retry-Logik

Ein häufiges Bug-Muster in selbst geschriebenen Retry-Mechanismen: Ein Skript merkt sich den Startzeitpunkt mit date +%s, berechnet in einer Schleife wiederholt die verstrichene Zeit gegen einen Timeout-Wert und bricht ab, sobald dieser überschritten ist. Läuft während dieser Schleife eine NTP-Korrektur, die die Systemzeit um mehrere Minuten zurücksetzt, kann die berechnete Differenz plötzlich negativ werden oder unerwartet klein bleiben, wodurch der Timeout niemals auslöst und die Schleife weit über die eigentlich gewünschte Zeit hinaus läuft, im schlimmsten Fall unbegrenzt.

Springt die Wall Clock dagegen nach vorne, etwa durch eine grobe Fehlkorrektur, kann ein Timeout fälschlich sofort auslösen, obwohl in Wirklichkeit kaum Zeit vergangen ist. Beide Szenarien sind in der Praxis selten, aber genau deshalb schwer zu reproduzieren und zu debuggen, wenn sie einmal auftreten. Wer Timeouts, Retry-Intervalle oder Ratenbegrenzungen implementiert, sollte deshalb grundsätzlich die Monotonic Clock verwenden, niemals die Wall Clock, denn nur die Monotonic Clock garantiert, dass eine gemessene Differenz stets der tatsächlich vergangenen Zeit entspricht.


#!/usr/bin/env bash
# Timeout loop that survives an NTP time jump during execution
set -euo pipefail

readonly TIMEOUT_SECONDS=30
start_mono="$(awk '{print $1}' /proc/uptime)"

while true; do
  now_mono="$(awk '{print $1}' /proc/uptime)"
  elapsed="$(echo "$now_mono - $start_mono" | bc)"

  if (( $(echo "$elapsed >= $TIMEOUT_SECONDS" | bc -l) )); then
    echo "[ERROR] Timeout after ${elapsed}s, giving up" >&2
    exit 1
  fi

  if curl -fsS -m 2 http://backend.local/health > /dev/null 2>&1; then
    echo "[OK] Backend is reachable after ${elapsed}s"
    break
  fi

  sleep 1
done

5. CLOCK_MONOTONIC_RAW und CLOCK_BOOTTIME: die Feinheiten

Neben der Standard-Monotonic-Clock kennt Linux zwei verwandte, aber unterschiedliche Varianten. CLOCK_MONOTONIC_RAW liefert die reine Hardware-Zählerzeit ohne jede NTP-Anpassung, auch nicht das sanfte Slewing, das CLOCK_MONOTONIC normalerweise erfährt. Diese Variante eignet sich für sehr präzise, kurzzeitige Messungen, bei denen selbst minimale Anpassungen durch den NTP-Dämon unerwünscht sind, etwa bei Benchmark-Messungen im Mikrosekundenbereich.

CLOCK_BOOTTIME unterscheidet sich in einem weiteren, oft übersehenen Detail: Während CLOCK_MONOTONIC während der Suspend-Phase eines Geräts, etwa eines Laptops im Standby, stehen bleibt, zählt CLOCK_BOOTTIME auch die Suspend-Zeit mit. Für Server ist dieser Unterschied meist irrelevant, da produktive Server üblicherweise nicht in den Suspend-Modus wechseln, für Laptops und mobile Geräte mit systemd-Timern kann er jedoch entscheidend sein, etwa wenn ein Timer nach dem Aufwachen aus dem Standby sofort nachgeholt werden soll.

6. Bash-Skripte robust gegen Zeitsprünge machen

Für die überwiegende Mehrheit administrativer Shell-Skripte reicht der bereits gezeigte Ansatz über /proc/uptime vollkommen aus, um Laufzeiten robust gegen Zeitsprünge zu messen. Ein zusätzliches, defensives Muster: Bei kritischen Skripten, deren Laufzeit überwacht werden soll, lohnt sich ein Vergleich zwischen der über die Monotonic Clock gemessenen Laufzeit und der über die Wall Clock gemessenen Laufzeit am Ende des Skripts. Eine große Diskrepanz zwischen beiden Werten deutet auf einen Zeitsprung während der Ausführung hin und kann als eigenständige Diagnoseinformation ins Log geschrieben werden.

Für Skripte, die Warteintervalle mit sleep umsetzen, ist die Monotonic Clock ohnehin implizit im Spiel: sleep selbst basiert intern auf einem monotonen Timer des Kernels und ist damit bereits robust gegen Wall-Clock-Sprünge, im Gegensatz zu selbst geschriebenen Warteschleifen, die die verstrichene Zeit manuell mit date berechnen, statt einfach sleep direkt zu nutzen.

7. Log-Zeitstempel: Wall Clock nötig, aber Vorsicht bei Deltas

Für Logdateien und Datenbank-Zeitstempel ist die Wall Clock unverzichtbar, denn ein Log-Eintrag muss zeigen, wann ein Ereignis im Kalendersinn tatsächlich stattgefunden hat, nicht wie viele Sekunden seit dem letzten Systemstart vergangen sind. Ein monotoner Zähler wäre für diesen Zweck bedeutungslos, da sein Referenzpunkt bei jedem Neustart auf null zurückspringt und keinerlei Bezug zu einem realen Kalenderdatum hat.

Vorsicht ist jedoch geboten, sobald aus zwei Wall-Clock-Zeitstempeln eine Zeitdifferenz berechnet werden soll, etwa um die Dauer zwischen zwei Log-Ereignissen zu bestimmen. Liegt zwischen beiden Zeitstempeln eine NTP-Korrektur, ist die berechnete Differenz nicht mehr die tatsächlich vergangene Zeit. Für reine Anzeige- und Aufbewahrungszwecke bleibt die Wall Clock also richtig, für die Berechnung von Zeitdifferenzen innerhalb eines laufenden Prozesses bleibt die Monotonic Clock die einzig korrekte Wahl.

8. systemd-Timer und die interne Monotonic-Logik

systemd-Timer-Units unterscheiden intern zwischen kalenderbasierten Ausdrücken wie OnCalendar, die auf der Wall Clock basieren, und monotonen Ausdrücken wie OnBootSec oder OnUnitActiveSec, die auf der Monotonic Clock basieren. Ein Timer mit OnUnitActiveSec=1h löst exakt eine Stunde nach dem letzten Start der zugehörigen Service-Unit aus, unabhängig davon, ob zwischenzeitlich die Wall Clock durch eine NTP-Korrektur verändert wurde, denn die interne Berechnung nutzt konsequent den monotonen Zähler des Kernels.

Dieser Unterschied erklärt, warum ein OnCalendar-Timer bei einer größeren manuellen Zeitkorrektur unter Umständen sofort oder mehrfach auslösen kann, während ein rein monotoner Timer von einer solchen Korrektur komplett unberührt bleibt. Für zeitkritische, wiederkehrende Wartungsintervalle, bei denen die exakte Wall-Clock-Uhrzeit irrelevant ist, aber ein zuverlässiger fester Abstand zwischen zwei Ausführungen zählt, ist ein monotoner Timer-Ausdruck deshalb oft die robustere Wahl gegenüber einem kalenderbasierten Ausdruck.

9. Clock-Typen im Überblick

Die folgende Tabelle fasst die wichtigsten Linux-Uhren und ihre jeweiligen Garantien zusammen, um die richtige Wahl je nach Anwendungsfall zu erleichtern.

Clock-Typ Kann springen? Läuft während Suspend? Typischer Einsatz
CLOCK_REALTIME Ja, vor und zurück Ja Kalenderzeit, Log-Zeitstempel, Datenbanken
CLOCK_MONOTONIC Nein, nur sanftes Slewing Nein, stoppt bei Suspend Timeouts, Laufzeitmessung, Retry-Logik
CLOCK_MONOTONIC_RAW Nein, auch kein Slewing Nein Hochpräzise Benchmarks im Mikrosekundenbereich
CLOCK_BOOTTIME Nein, nur sanftes Slewing Ja, zählt Suspend-Zeit mit Laptops, mobile Geräte, Timer nach Standby

Als Faustregel gilt: Für alles, was angezeigt, gespeichert oder mit einem Kalenderdatum verglichen werden soll, ist CLOCK_REALTIME richtig. Für alles, was eine Dauer oder ein Zeitintervall misst, ist CLOCK_MONOTONIC oder eine ihrer Varianten die korrekte und robuste Wahl, unabhängig davon, wie oft die Systemzeit im Hintergrund korrigiert wird.

Mironsoft

Systemprogrammierung, Backend-Robustheit und Linux-Infrastruktur

Timeouts und Retry-Logik, die Zeitsprünge überstehen?

Wir prüfen bestehende Skripte und Anwendungen auf Wall-Clock-basierte Zeitmessung und ersetzen kritische Stellen durch robuste, monotone Zeitberechnung, die auch bei NTP-Korrekturen zuverlässig bleibt.

Code-Audit

Analyse auf fehleranfällige Wall-Clock-Nutzung in Timeouts und Retries

Refactoring

Umstellung kritischer Zeitmessungen auf CLOCK_MONOTONIC-basierte Logik

systemd-Timer-Design

Passende Wahl zwischen OnCalendar und monotonen Timer-Ausdrücken

10. Zusammenfassung

Monotonic Clock vs. Wall Clock ist der zentrale Unterschied zwischen zwei Uhren, die Linux gleichzeitig führt: CLOCK_REALTIME liefert die tatsächliche Kalenderzeit, kann sich aber durch NTP-Korrekturen oder manuelle Eingriffe jederzeit ändern, sogar rückwärts. CLOCK_MONOTONIC garantiert dagegen einen niemals rückläufigen Zählerwert und ist damit das einzig korrekte Werkzeug für Timeouts, Retry-Intervalle und Laufzeitmessungen.

Varianten wie CLOCK_MONOTONIC_RAW und CLOCK_BOOTTIME decken Spezialfälle wie Hochpräzisions-Benchmarks oder Suspend-bewusste Timer ab. Für Log-Zeitstempel und Datenbanken bleibt die Wall Clock unverzichtbar, für die Berechnung von Zeitdifferenzen innerhalb eines laufenden Prozesses gehört ausschließlich die Monotonic Clock zum Einsatz. Wer diese Unterscheidung konsequent einhält, vermeidet Bugs, die erst bei der nächsten größeren NTP-Korrektur sichtbar werden.

Monotonic Clock vs. Wall Clock, das Wichtigste auf einen Blick

Wall Clock kann springen

CLOCK_REALTIME kann durch NTP oder manuelle Eingriffe vor und zurück springen.

Monotonic Clock läuft immer vorwärts

CLOCK_MONOTONIC garantiert per Definition, niemals rückwärts zu laufen.

Timeouts brauchen Monotonic

Laufzeitmessung, Retry-Logik und Timeouts sollten ausschließlich Monotonic Clock nutzen.

Logs brauchen Wall Clock

Für Kalenderzeitstempel bleibt CLOCK_REALTIME nötig, für Deltas ist sie ungeeignet.

11. FAQ: Monotonic Clock vs. Wall Clock

1Unterschied zwischen Monotonic Clock und Wall Clock?
Wall Clock liefert Kalenderzeit und kann springen, Monotonic Clock läuft garantiert niemals rückwärts.
2Warum kann die Wall Clock zurückspringen?
NTP-Korrekturen, manuelle Anpassungen oder eine ungenaue Hardware-Uhr beim Start.
3Welche Clock für Timeouts?
Immer CLOCK_MONOTONIC verwenden.
4Wie messe ich Monotonic-Zeit in Bash?
Über die erste Spalte von /proc/uptime.
5Unterschied MONOTONIC vs. MONOTONIC_RAW?
RAW ohne jede NTP-Anpassung, MONOTONIC mit sanftem Slewing.
6Was ist CLOCK_BOOTTIME?
Wie MONOTONIC, zählt aber Suspend-Zeit mit. Relevant für Laptops.
7Monotonic Clock für Log-Zeitstempel?
Nein, Logs brauchen die Wall Clock für reale Kalenderzeit.
8OnCalendar vs. OnUnitActiveSec?
OnCalendar nutzt Wall Clock, OnUnitActiveSec nutzt Monotonic Clock.
9Ist sleep von Zeitsprüngen betroffen?
Nein, sleep basiert intern bereits auf einem monotonen Timer.
10Warum ist date +%s ungeeignet für Laufzeiten?
Es liefert die Wall Clock, die durch NTP springen kann.