Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen …

netcup Schwierigkeit: Fortgeschritten Ratgeber

Wann reicht der kleine Server nicht mehr? Fünf Upgrade-Signale

Fünf messbare Signale zeigen, wann ein VPS zu klein wird – und wann Aufräumen billiger ist als Upgraden. Mit echten Zahlen aus 80 Tagen Dauerbetrieb.

· Zuletzt aktualisiert: · 14 Min. Lesezeit
Inhaltsverzeichnis

„Der Server ist zu klein" ist selten eine Messung und meistens ein Gefühl. Dieser Artikel ersetzt das Gefühl durch fünf Zahlen, die du in zwei Minuten selbst ablesen kannst.

Kurz gesagt

Ein größerer Server lohnt sich in drei Fällen: wenn der Maschine selbst der Speicher ausgeht (available dauerhaft unter rund 10 Prozent, CONSTRAINT_NONE im Kernel-Log), wenn der 15-Minuten-Load dauerhaft über der Kernzahl liegt und wenn die Platte knapp ist, obwohl docker system df nichts Aufräumbares mehr zeigt. Bremst dagegen die Platte (wa hoch, us niedrig) oder stößt ein Container an sein eigenes mem_limit, bringt ein Upgrade nichts. Dauerhaft zweistellige Steal Time ist ein Fall für ein Support-Ticket. Vier der fünf Signale stehen in einer einzigen vmstat-Ausgabe.

Die Grundlage

Alle Werte unten stammen von einem netcup VPS 1000 G12 mit 4 vCPU und 7,8 GiB RAM, der zum Zeitpunkt der Messung seit 80 Tagen durchlief. Erhoben sind sie unter kontrollierter Last.

Das Ergebnis ist eine Entscheidungsroutine. Am Ende kennst du fünf Signale, den Befehl, der jedes davon zeigt, und die Schwelle, ab der ein größerer Server das Problem wirklich löst. Genauso wichtig ist der umgekehrte Fall: Bei zwei der fünf Signale ist ein Upgrade rausgeworfenes Geld, weil die Ursache woanders liegt.

Das Schöne daran: Vier der fünf Signale stehen in einer einzigen Ausgabe, und das Werkzeug dafür ist auf jedem Debian schon installiert.

Zum Ablesen brauchst du:

  • Ein Linux-Server mit Root-Zugang, auf dem schon etwas läuft – ein leerer Server sagt nichts.
  • vmstat (Paket procps, auf Debian 13 vorinstalliert). Mehr braucht es nicht.
  • Hilfreich, aber nicht nötig: ein laufendes Monitoring mit Grafana und Prometheus. Die Momentaufnahme unten beantwortet „ist jetzt gerade etwas eng?"; für „seit wann wird es enger?" brauchst du eine Zeitreihe.
🍳 Empfehlung Anzeige

VPS 1000 G12.5

4 vCore · 8 GB RAM · 128 GB SSD

ab 14,50 €/Monat

Der Server, auf dem alle Zahlen dieses Artikels gemessen wurden.

Zu netcup →

💶 1 Monat gratis:

Einmal einlösbar, gilt für VPS 1000 G12.5. Im Warenkorb einlösen →

💶 5,95 € Gutschein für netcup-Neukunden: immer gültig · nicht für Domains und VPS Lite

Alle netcup-Gutscheine →

Eine Ausgabe, vier Signale

vmstat zeigt im Sekundentakt, woran der Server gerade hängt. Der erste Block ist immer ein Mittelwert seit dem Systemstart – den ignorierst du und liest ab der zweiten Zeile:

Terminal
vmstat 1 5
Ausgabe
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st gu
 1  0      0 3475108 271400 3831564    0    0    36    68  151    0  0  0 100  0  0  0
 0  0      0 3474844 271400 3831576    0    0     0     0  165  158  0  0 100  0  0  0
 0  0      0 3474844 271400 3831576    0    0     0     4  116  103  0  0 100  0  0  0

So sieht ein Server aus, dem langweilig ist. Sechs Spalten tragen die Aussage:

SpalteBedeutungSignal
rProzesse, die rechnen wollenWarteschlange vor den Kernen
bProzesse, die auf die Platte wartenPlatte am Anschlag
free / cachefreier Speicher, DateicacheSpeicherdruck
si / soAuslagern auf Swapauf dem VPS immer 0 – siehe Signal 1
waCPU wartet auf Ein-/AusgabePlatte, nicht CPU
stgeklaute CPU-Zeitüberbuchter Wirt

Die fünfte Zahl, der Plattenfüllstand, kommt mit Signal 5 dazu. Dafür reicht df.

Signal 1: der Speicher endet ohne Vorwarnung

Die bekannteste Faustregel lautet: Wenn der Server anfängt zu swappen, ist der RAM zu klein. Auf einem netcup-VPS greift sie nicht, denn es gibt keinen Swap:

Terminal
free -h
Ausgabe
               total        used        free      shared  buff/cache   available
Mem:           7.8Gi       721Mi       7.0Gi       664Ki       261Mi       7.1Gi
Swap:             0B          0B          0B

Swap: 0B – und /proc/swaps enthält nur die Kopfzeile. Das hat eine unangenehme Folge: Die Spalten si und so in vmstat bleiben für immer auf 0. Das Vorwarnsignal, auf das die halbe Ratgeberliteratur zeigt, kann auf dieser Maschine gar nicht auslösen.

Was stattdessen passiert, haben wir gemessen. Ein Testprozess hat in 200-MiB-Schritten Speicher belegt und auch wirklich angefasst, während vmstat mitlief:

Ausgabe
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 2749328 199352 4218256    0    0   492     0  296  171  0 11 88  0  0
 0  0      0 1513180 199352 4218256    0    0     0     0  222   86  0 13 87  0  0
 0  0      0  684544 199352 4218256    0    0     0   140  190  125  1  6 94  0  0
 0  0      0  200836 199352 4218256    0    0     0     0  175   81  1  6 93  0  0
 0  0      0  149284 152392 3782580    0    0     0     0  324  207  1 13 86  0  0
 0  0      0  141984 152376 3371156    0    0     0     0  309  209  1 11 88  0  0
 0  0      0  140092  49936 2163436    0    0     0     0  511  243  1 18 82  0  0

Lies die Zeilen von oben nach unten: free fällt von 2,7 GB auf 140 MB. Dann beginnt der Kernel, den Dateicache zu opfern – cache sinkt von 4,2 GB auf 2,1 GB. si und so stehen die ganze Zeit auf 0. Und dann ist Schluss:

Terminal
journalctl -k --since "-5min" --grep "oom-kill|Out of memory"
Ausgabe
python3 invoked oom-killer: gfp_mask=0x140dca(GFP_HIGHUSER_MOVABLE|__GFP_COMP|__GFP_ZERO), order=0, oom_score_adj=1000
oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=user.slice,mems_allowed=0,global_oom,task_memcg=/user.slice/user-0.slice/session-6076.scope,task=python3,pid=3065035,uid=0
Out of memory: Killed process 3065035 (python3) total-vm:6571320kB, anon-rss:6459404kB, file-rss:116kB, shmem-rss:0kB, UID:0 pgtables:12712kB oom_score_adj:1000

Vom „noch 2,7 GB frei" bis zum beendeten Prozess lagen sieben Sekunden. Ohne Swap gibt es keine zähe Phase, in der dir der Server mitteilt, dass es eng wird. Er läuft normal – und dann fehlt ein Dienst.

Die Zahl, auf die du schaust, heißt available

Nicht free. Der Kernel benutzt jeden ungenutzten Block als Dateicache, deshalb ist free auf einem eingelaufenen Server immer klein und sagt nichts. available schätzt, wie viel sich ohne Auslagern noch beschaffen lässt. Fällt dieser Wert dauerhaft unter rund 10 Prozent des Gesamtspeichers, bist du eine unglückliche Anfrage vom nächsten Abschuss entfernt.

Wer abgeschossen wurde, entscheidet die Rechnung

In derselben Kernel-Zeile steht das Feld, an dem die Kaufentscheidung hängt. Auf diesem Server haben wir beide Varianten im Protokoll. Oben, gerade eben: constraint=CONSTRAINT_NONE zusammen mit global_oom. Und am 9. September:

Ausgabe
oom-kill:constraint=CONSTRAINT_MEMCG,nodemask=(null),cpuset=docker-c7122b11…scope,oom_memcg=/system.slice/docker-c7122b11…scope,task=tail,pid=589430,uid=0
Memory cgroup out of memory: Killed process 589430 (tail) total-vm:132096kB,anon-rss:130432kB,file-rss:772kB,shmem-rss:0kB,UID:0 pgtables:304kB oom_score_adj:0

Der Unterschied ist die ganze Diagnose:

  • CONSTRAINT_MEMCG heißt: Ein Container ist an sein eigenes Limit gestoßen, 130 MB bei einem mem_limit von 128 MB. Der Server hatte zu dem Zeitpunkt Gigabytes frei. Ein größerer Server ändert daran nichts – das Limit gehört korrigiert, siehe Docker-Container absichern.
  • CONSTRAINT_NONE mit global_oom heißt: Der Maschine selbst ist der Speicher ausgegangen. Erst das ist ein Upgrade-Signal.

Wer diese Unterscheidung überspringt, bestellt den doppelt so großen Server und sieht den Container am nächsten Tag wieder sterben. Ein exit 137 allein verrät dir nicht, welcher der beiden Fälle vorliegt – beide beenden den Prozess gleich. Die Antwort steht nur im Kernel-Log.

Signal 2: die Warteschlange vor den Kernen

Der Load-Average sagt für sich genommen wenig, weil niemand dazuschreibt, wie viele Kerne die Maschine hat. Interessant wird er erst geteilt durch nproc:

Terminal
nproc; cat /proc/loadavg

Zum Messen haben wir eine Referenzaufgabe gebaut, die immer gleich teuer ist: der SHA-256-Hash über eine Gigabyte-Datei, die schon im Cache liegt – reine Rechenzeit, keine Platte. Im Leerlauf, dreimal hintereinander:

Ausgabe
0.88 s
0.88 s
0.89 s

Dann acht Rechenschleifen auf vier vCPU, also eine mehr als doppelte Überbuchung:

Ausgabe
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 8  0      0 2406468 271400 4882092    0    0     0     0  980  905 98  1  0  0  1
 8  0      0 2406468 271400 4882092    0    0     0     0  985  920 99  0  0  0  1

Load-Average 6,15 bei vier Kernen, r steht auf 8, die CPU ist zu 99 Prozent in Anwendungscode. Dieselbe Aufgabe braucht jetzt:

Ausgabe
2.16 s
2.20 s

Zweieinhalbmal so lang. Nach dem Abschalten der Last ist sie sofort wieder bei 0,91 s – kein Nachwirken, keine kaputte Maschine. Genau so verhält sich ein Server, der zu wenig Rechenzeit hat: Alles wird langsamer, nichts geht kaputt.

Daraus wird eine brauchbare Faustregel. Teile r durch die Zahl der Kerne, und du hast ungefähr den Faktor, um den gerade alles langsamer ist. Neun rechenwillige Prozesse auf vier Kernen sagen Faktor 2,25 voraus, gemessen waren es 2,45.

Die Schwelle: Steht der 15-Minuten-Wert dauerhaft über der Kernzahl, ist der Server zu klein für das, was er tun soll. Kurze Spitzen beim nächtlichen Backup oder einem docker compose pull sind dagegen völlig normal und kein Grund für irgendetwas.

Signal 3: wenn die Platte bremst, hilft kein größerer Server

Jetzt der Fall, der am häufigsten falsch gelesen wird. Wir haben vier parallele Schreiber auf die Systemplatte losgelassen, am Dateicache vorbei:

Terminal
for i in 1 2 3 4; do dd if=/dev/zero of=/var/tmp/p$i.bin bs=1M count=8192 oflag=direct & done
Ausgabe
nach 15 s: 2.07 1.95 1.27 | r=0 b=4 us=0% wa=72%
nach 30 s: 2.50 2.05 1.31 | r=0 b=4 us=0% wa=97%
nach 45 s: 2.83 2.15 1.35 | r=0 b=4 us=0% wa=97%

Ein Load-Average von 2,8 – bei null Prozent CPU-Nutzung. Das ist kein Messfehler: Linux zählt in den Load-Average auch die Prozesse, die ununterbrechbar auf die Platte warten. Wer nur auf den Load schaut, bestellt hier mehr Kerne und bekommt exakt nichts.

Die Zahlen dahinter: Ein einzelner Strom schreibt 678 MB/s und liest 686 MB/s. Vier parallele Ströme schreiben zusammen auch nur rund 700 MB/s – die NVMe ist am Anschlag, und die drei zusätzlichen Prozesse stehen bloß in der Spalte b.

Was dieses Signal bedeutet, ist unbequem: Ein größeres VPS-Paket gibt dir mehr vCPU und mehr RAM, aber nicht mehr Platten-Durchsatz. Wenn wa dein Engpass ist, hilft ein anderer Zuschnitt der Arbeit – Datenbank-Indizes, weniger gleichzeitige Jobs, ein eigenes Volume für die schreibintensive Anwendung – oder ein Produkt mit anderem Storage, nicht die nächste Größe desselben.

Tipp

Dauerhaft hohes wa bei gleichzeitig kleinem Durchsatz (bi/bo niedrig) ist ein anderes Problem als wa bei vollem Durchsatz. Volles bo heißt „Gerät am Limit". Niedriges bo bei hohem wa heißt meist: viele winzige Schreibvorgänge, typischerweise eine Datenbank ohne passende Indizes oder ein Logger, der jede Zeile synchron wegschreibt.

Signal 4: Steal Time, und warum sie meistens eine Legende ist

In jedem Forum steht, geteilte vCPU seien unbrauchbar, weil die Nachbarn die Rechenzeit wegnehmen. Die Spalte st misst genau das. Für diesen Server über die vollen 80 Tage Laufzeit:

Terminal
awk '/^cpu /{t=$2+$3+$4+$5+$6+$7+$8+$9; printf "%.3f %%\n", 100*$9/t}' /proc/stat
Ausgabe
0.001 %

Ein Tausendstel Prozent. Selbst während unserer Volllast-Messung stand st auf 1. Die Legende hält auf dieser Maschine nicht stand, und dasselbe Bild zeigte schon der Benchmark des VPS 1000.

Trotzdem gehört die Spalte in die Routine – denn wenn sie ausschlägt, ist sie das einzige Signal, das du selbst gar nicht beheben kannst. Dauerhaft zweistellige Werte bedeuten, dass der Wirt überbucht ist. Dann hilft kein Aufräumen und kein größeres Paket beim selben Wirt, sondern ein Support-Ticket mit deinen Messwerten.

Signal 5: der Plattenfüllstand lügt am lautesten

Das letzte Signal ist das einzige, bei dem Aufräumen fast immer billiger ist als Upgraden. Auf unserem Server sieht es zunächst entspannt aus:

Terminal
df -h /
Ausgabe
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda4       251G   73G  169G  31% /

31 Prozent, kein Grund zur Sorge. Bis man fragt, wer die 73 GB belegt:

Terminal
docker system df
Ausgabe
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          107       1         74.58GB   68.43GB (91%)
Containers      1         1         8.192kB   0B (0%)
Local Volumes   0         0         0B        0B
Build Cache     33        0         209.5MB   4.096kB

107 Images, von denen genau eines benutzt wird. 68 GB sind Reste von Tests, die längst abgeräumt wurden – aber eben nur die Container, nicht die Images. Das ist kein Upgrade-Fall, das ist ein docker image prune -a und vorher ein Blick, ob wirklich nichts davon gebraucht wird.

Auf einem aktuellen VPS 1000 der Generation G12.5 wäre dieselbe Halde schon mehr als die Hälfte der Platte: Der hat 128 GB statt der 251 GB unseres G12. Warum die Generation hier zählt, steht im 100-Tage-Bericht.

Unter Docker 29 liegen die Images woanders

Die naheliegende Suche führt in die Irre: du -sh /var/lib/docker meldet auf diesem Server 188 MB. Die 70 GB liegen in /var/lib/containerd, weil Docker seit Version 29 standardmäßig den containerd-Image-Store benutzt (docker info zeigt driver-type: io.containerd.snapshotter.v1). Wer nach altem Rezept sucht, findet nichts und vermutet den Fehler woanders.

Zwei weitere Kandidaten, die sich leise ansammeln: das Journal (journalctl --disk-usage, hier 279 MB – begrenzbar über SystemMaxUse in /etc/systemd/journald.conf) und alte Images, die dein Update-Lauf hinterlässt; wie man das automatisiert, steht in Docker-Stack aktuell halten.

Auf Debian 13 ist /tmp eine RAM-Disk

findmnt /tmp zeigt tmpfs 3.9G. Was du dort ablegst, belegt Arbeitsspeicher, nicht Platte – es taucht in free -h als shared auf und ist nach einem Neustart weg. Eine 4-GiB-Datei nach /tmp bricht deshalb mittendrin ab, während df -h / unverändert 31 Prozent meldet – die Platte war nie das Problem. Große Zwischendateien gehören nach /var/tmp.

Die Entscheidung

SignalWoran du es siehstUnd dann?
Speicheravailable dauerhaft < 10 %, CONSTRAINT_NONE im Kernel-LogUpgrade
Container-OOMCONSTRAINT_MEMCG im Kernel-Logmem_limit korrigieren
Rechenzeit15-Minuten-Load dauerhaft > Kernzahl, us hochUpgrade
Ein-/Ausgabewa hoch, us niedrig, b > 0Arbeit umbauen oder Storage wechseln
Stealst dauerhaft zweistelligSupport-Ticket
Plattedf knapp und docker system df sauberUpgrade – sonst aufräumen

Drei der sechs Zeilen enden nicht bei „größerer Server". Das ist der eigentliche Nutzen der Routine: Sie verhindert ein Upgrade, das nichts bringt, genauso zuverlässig, wie sie eines begründet, das etwas bringt.

Und falls die Entscheidung am Ende doch auf „größer" fällt: Die Tarife mit Preisen stehen in der netcup-Übersicht, und ein Snapshot vor dem Umzug kostet nichts außer ein paar Minuten.

Wenn es nicht funktioniert

vmstat zeigt dauerhaft 100 Prozent id, obwohl die Seite spürbar langsam ist. Dann ist der Engpass nicht auf diesem Server. Prüfe die Antwortzeit direkt am Dienst statt über die Domain – wenn der Container schnell antwortet und der Browser trotzdem wartet, liegt es am Weg dorthin: DNS, TLS-Handshake oder ein überlastetes Netz, nicht an CPU oder RAM.

Im Kernel-Log steht gar nichts, obwohl ein Container verschwunden ist. journalctl -k zeigt nur echte OOM-Abschüsse. Beendet sich ein Dienst selbst, steht der Grund in seinem eigenen Log: docker compose logs --tail 50 DEIN_DIENST. Ein exit 137 ohne passende Kernel-Zeile ist meistens ein docker stop mit abgelaufener Frist, kein Speicherproblem.

Der Load-Average ist hoch, aber r und b stehen beide auf 0. Du liest die erste vmstat-Zeile. Die ist ein Mittelwert seit dem Systemstart und auf einem Server mit 80 Tagen Laufzeit praktisch bedeutungslos. Nimm vmstat 1 5 und werte ab der zweiten Zeile aus.

free -h meldet fast keinen freien Speicher, der Server läuft aber tadellos. Das ist der Normalzustand. Der Kernel füllt ungenutzten Speicher mit Dateicache und gibt ihn sofort wieder her, wenn jemand ihn braucht. Entscheidend ist die Spalte available; free darf getrost nahe null stehen.

Viel Reclaimable, aber docker image prune -a gibt kaum etwas frei. Dann hängen die Images noch an gestoppten Containern. Erst docker container prune, dann die Images – oder in einem Rutsch docker system prune -a, nachdem du geprüft hast, dass alle gewünschten Stacks wirklich laufen.

Dein Problem ist nicht dabei? Alle Fehlermeldungen durchsuchen →

Grenzen dieser Aussage

Alle Zahlen stammen von einem einzigen netcup VPS 1000 der Generation G12 mit 4 vCPU, 7,8 GiB RAM und Debian 13.6, gemessen am 04.10.2026 unter kontrollierter Last. Dass die Steal Time über 80 Tage bei einem Tausendstel Prozent lag, gilt für diese Maschine; auf einem anderen Wirt kann sie anders aussehen. Das Speicherverhalten aus Signal 1 gilt für einen Server ohne Swap, wie ihn netcup als VPS ausliefert. Ein aktueller VPS 1000 der Generation G12.5 hat 128 GB statt 251 GB Platte, dieselbe Image-Halde wäre dort schon mehr als die Hälfte davon.

Die Schwellen sind Faustregeln: r geteilt durch die Kernzahl sagte Faktor 2,25 voraus, gemessen waren 2,45. Und die Routine ist eine Momentaufnahme. Ob es seit Wochen enger wird, zeigt erst eine Zeitreihe aus dem Monitoring.

Wartung & Backups

Diese Routine ist nichts, was man einmal durchläuft. Zwei Gewohnheiten reichen:

Einmal im Monat, zwei Minuten: vmstat 1 5, free -h, df -h / und docker system df. Schreib dir die vier Werte auf – der Verlauf über ein halbes Jahr ist aussagekräftiger als jede Momentaufnahme, und er zeigt dir ein Upgrade Wochen vorher an.

Einmal eingerichtet, dauerhaft: Ein Alarm auf available und auf den Plattenfüllstand. Beides lässt sich mit dem bestehenden Grafana-und-Prometheus-Setup abbilden; wer es schlanker mag, nimmt einen Push-Dienst wie in ntfy-Benachrichtigungen. Die Schwelle für den Speicher setzt du bewusst tief: Ohne Swap ist zwischen „wird eng" und „Dienst ist weg" keine Zeit, in der ein Alarm dich noch rechtzeitig erreicht, wenn er erst bei 2 Prozent auslöst.

Ein Backup gehört vor jede Konsequenz aus dieser Messung – egal ob du aufräumst oder umziehst. Für beides reicht die Routine aus Backups mit restic; vor einem Produktwechsel zusätzlich ein Snapshot im netcup-Kundenbereich.

Feedback per E-Mail: feedback@serverkueche.de

Das könnte dir auch schmecken