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.
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(Paketprocps, 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.
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.
💶 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
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:
vmstat 1 5procs -----------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 0So sieht ein Server aus, dem langweilig ist. Sechs Spalten tragen die Aussage:
| Spalte | Bedeutung | Signal |
|---|---|---|
r | Prozesse, die rechnen wollen | Warteschlange vor den Kernen |
b | Prozesse, die auf die Platte warten | Platte am Anschlag |
free / cache | freier Speicher, Dateicache | Speicherdruck |
si / so | Auslagern auf Swap | auf dem VPS immer 0 – siehe Signal 1 |
wa | CPU wartet auf Ein-/Ausgabe | Platte, nicht CPU |
st | geklaute 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:
free -h total used free shared buff/cache available
Mem: 7.8Gi 721Mi 7.0Gi 664Ki 261Mi 7.1Gi
Swap: 0B 0B 0BSwap: 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:
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 0Lies 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:
journalctl -k --since "-5min" --grep "oom-kill|Out of memory"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:1000Vom „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
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:
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:0Der Unterschied ist die ganze Diagnose:
CONSTRAINT_MEMCGheißt: Ein Container ist an sein eigenes Limit gestoßen, 130 MB bei einemmem_limitvon 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_NONEmitglobal_oomheiß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:
nproc; cat /proc/loadavgZum 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:
0.88 s
0.88 s
0.89 sDann acht Rechenschleifen auf vier vCPU, also eine mehr als doppelte Überbuchung:
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 1Load-Average 6,15 bei vier Kernen, r steht auf 8, die CPU ist zu 99 Prozent in
Anwendungscode. Dieselbe Aufgabe braucht jetzt:
2.16 s
2.20 sZweieinhalbmal 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:
for i in 1 2 3 4; do dd if=/dev/zero of=/var/tmp/p$i.bin bs=1M count=8192 oflag=direct & donenach 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
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:
awk '/^cpu /{t=$2+$3+$4+$5+$6+$7+$8+$9; printf "%.3f %%\n", 100*$9/t}' /proc/stat0.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:
df -h /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:
docker system dfTYPE 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.096kB107 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
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
| Signal | Woran du es siehst | Und dann? |
|---|---|---|
| Speicher | available dauerhaft < 10 %, CONSTRAINT_NONE im Kernel-Log | Upgrade |
| Container-OOM | CONSTRAINT_MEMCG im Kernel-Log | mem_limit korrigieren |
| Rechenzeit | 15-Minuten-Load dauerhaft > Kernzahl, us hoch | Upgrade |
| Ein-/Ausgabe | wa hoch, us niedrig, b > 0 | Arbeit umbauen oder Storage wechseln |
| Steal | st dauerhaft zweistellig | Support-Ticket |
| Platte | df knapp und docker system df sauber | Upgrade – 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

netcup VPS 1000 G12 im Benchmark: wie schnell ist er?

100 Tage netcup: was dir vorher niemand sagt
