Read in English · Leer en español · Lire en français
Abschnitt 2.4 von 2.8 · Mittelstufe · 24 Min. Lesezeit
Performance und Skalierbarkeit: Latenz, Durchsatz, Perzentile und Last
Videolektion
5 Min. · auf Englisch gesprochen, mit UntertitelnNur anhören (Audio)
Transkript lesen
Performance ist die Qualität, die zuerst genannt und am schlechtesten spezifiziert wird. In dieser Lektion lernen Sie die Handvoll Ideen und Formeln kennen, mit denen Fachleute sie richtig angehen.
Stellen Sie sich einen Supermarkt vor. Wie lange Sie an der Kasse verbringen, ist die Latenz: wie lange eine Arbeitseinheit dauert. Wie viele Kunden die Kassen in einer Stunde bedienen, ist der Durchsatz: wie viel Arbeit pro Zeiteinheit erledigt wird. Eine gute Anforderung nennt beides, zusammen mit der Last, bei der es gilt. Ihre Zeit an der Kasse besteht teils aus dem Scannen, der eigentlichen Arbeit, und teils aus der Schlange vor Ihnen. Sind die Kassen nur halb ausgelastet, stehen Sie kaum an. Sind sie fast immer belegt, werden die Schlangen sehr schnell sehr lang, obwohl jeder Scan gleich lange dauert.
Software funktioniert genauso. Die Antwortzeit, die ein Client sieht, ist alles zwischen dem Senden einer Anfrage und dem Erhalt der Antwort. Ein Teil davon ist Warten in einer Queue, weil der Worker mit der Anfrage eines anderen beschäftigt ist. Ein Teil ist die Bedienzeit: die eigentliche Arbeit. Die Netzwerkzeit kommt in beiden Richtungen hinzu. Die beiden Teile brauchen unterschiedliche Mittel. Eine schnellere Abfrage senkt die Bedienzeit. Nur mehr Kapazität oder weniger Last senkt die Wartezeit, und unter Last überwiegt meist das Warten. Eine Abfrage dauert vielleicht fünf Millisekunden, wartet aber dreihundert auf eine freie Verbindung.
Darum führen Mittelwerte in die Irre. Ein Suchservice protokolliert tausend Antwortzeiten. Neunhundert dauern achtzig Millisekunden, achtzig dauern hundertfünfzig, fünfzehn dauern tausendzweihundert und fünf dauern viertausend. Der Mittelwert liegt bei hundertzweiundzwanzig Millisekunden, was gut aussieht. Fachleute verwenden stattdessen Perzentile. Das fünfzigste Perzentil, also der Median, ist der Wert, den die Hälfte der Anfragen unterbietet. Hier sind das achtzig Millisekunden. Das fünfundneunzigste Perzentil, p fünfundneunzig, ist der Wert, den fünfundneunzig Prozent der Anfragen unterbieten: hundertfünfzig Millisekunden. Aber p neunundneunzig liegt bei tausendzweihundert Millisekunden. Und p neunundneunzig Komma neun liegt bei viertausend Millisekunden. Zwei Prozent der Benutzer warten also länger als eine Sekunde. Bei dreihundert Suchanfragen pro Sekunde sind das sechs Menschen in jeder Sekunde. Eine als Mittelwert formulierte Anforderung würde dieses System durchlassen. Eine in Perzentilen formulierte lässt es zu Recht durchfallen.
Das langsame Ende der Verteilung heißt Tail. Ein Benutzer, der vierzig Ressourcen lädt, um eine Seite zu sehen, wartet auf die langsamste dieser vierzig, nicht auf den Durchschnitt. Ein seltenes Ein-Prozent-Ereignis betrifft also etwa ein Drittel der Seitenaufrufe. In großen Systemen kann sich eine Anfrage auf hundert Server auffächern und auf alle warten. Ist jeder davon einmal von hundert langsam, ist die Anfrage des Benutzers in etwa dreiundsechzig Prozent der Fälle langsam.
Littles Gesetz ist die nützlichste einzelne Formel der Kapazitätsplanung. Die Zahl der laufenden Anfragen ist gleich der Ankunftsrate multipliziert mit der Zeit, die jede darin verbringt. Wenden wir es an. Ein Fahrtenservice eines Fahrdienstes verarbeitet zur abendlichen Spitzenzeit eintausendachthundert Anfragen pro Sekunde. Jede Anfrage belegt eine Datenbankverbindung vierzig Millisekunden lang. Im Mittel sind also eintausendachthundert mal null Komma null vier, also zweiundsiebzig Verbindungen, gleichzeitig belegt. Aber sechs Instanzen mit je zehn Verbindungen ergeben nur sechzig. Anfragen werden auf Verbindungen warten, und die Antwortzeiten steigen, bis Timeouts einsetzen. Um den Pool höchstens zu etwa siebzig Prozent auszulasten, brauchen Sie zweiundsiebzig geteilt durch null Komma sieben, etwa hundertdrei Verbindungen, also rund achtzehn pro Instanz.
Warum diese Reserve? Diese Kurve zeigt eine Warteschlange mit einem Server und einer Bedienzeit von zwanzig Millisekunden. Bis fünfzig Prozent Belegung beträgt die mittlere Antwortzeit nur vierzig Millisekunden. Bei achtzig Prozent Belegung sind es hundert Millisekunden. Bei neunzig Prozent verdoppelt sie sich auf zweihundert. Darüber steigt sie fast senkrecht an. Flach, dann ein Knick, dann eine Klippe. Planen Sie also nie, kritische Ressourcen nahe Volllast zu betreiben.
Skalierbarkeit ist die Fähigkeit, durch zusätzliche Ressourcen mehr Last zu bewältigen. Scale-up gibt einem Rechner mehr Leistung. Das ist einfach, stößt aber an harte Grenzen und steigende Preise. Scale-out fügt weitere Rechner hinzu. Es gibt keine feste Obergrenze, aber die Software muss dafür entworfen sein. Und Parallelität hat Grenzen. Amdahls Gesetz besagt: Wenn zehn Prozent der Arbeit Schritt für Schritt erledigt werden müssen, kann keine Zahl von Prozessoren den Job mehr als zehnmal schneller machen. Schlimmer noch: Daten zwischen Knoten konsistent zu halten, kostet etwas, und diese Kosten wachsen schnell, sodass weitere Knoten ab einem gewissen Punkt die Kapazität sogar senken. Suchen Sie nach den versteckten seriellen Teilen, etwa einer einzelnen Sperre oder einem zentralen Koordinator.
Der vollständige Abschnitt rechnet Amdahls Gesetz und das Universal Scalability Law durch und listet die wichtigsten Performance-Taktiken auf. Als Nächstes, in Abschnitt zwei Punkt fünf, geht es um Verfügbarkeit und Zuverlässigkeit. Bis gleich.
Was Sie wissen müssen
- Latenz ist, wie lange eine Arbeitseinheit dauert; Durchsatz ist, wie viel Arbeit pro Zeiteinheit erledigt wird. Eine Performance-Anforderung sollte beides angeben, zusammen mit der Last, bei der es gilt.
- Die Antwortzeit ist Bedienzeit plus Wartezeit (plus Netzwerkzeit); unter Last überwiegt meist die Wartezeit.
- Legen Sie Perzentile wie p95 und p99 fest und überwachen Sie sie, nicht Mittelwerte; in Fan-out-Systemen wird eine seltene langsame Antwort eines Servers für Benutzer zur Regel (Dean und Barroso, 2013).
- Littles Gesetz, L = λ × W, verknüpft Anfragerate, Antwortzeit und Nebenläufigkeit und ist die Grundlage für die Dimensionierung von Pools und Limits.
- In einem Warteschlangenmodell mit einem Server beträgt die mittlere Antwortzeit S ÷ (1 − ρ); sie verdoppelt sich also zwischen 80 % und 90 % Auslastung. Halten Sie kritische Ressourcen deutlich unterhalb der Sättigung.
- Amdahls Gesetz begrenzt die Beschleunigung bei einem seriellen Anteil s auf 1 ÷ s; das Universal Scalability Law ergänzt Kohärenzkosten, durch die die Kapazität einen Höchstwert erreicht und dann sinkt.
Zwei verschiedene Fragen: wie schnell und wie viel
Performance ist die Qualität, die zuerst genannt und am schlechtesten spezifiziert wird. Sie umfasst zwei verschiedene Fragen. Latenz fragt, wie lange eine Arbeitseinheit dauert: wie viele Millisekunden zwischen dem Tippen auf „Bezahlen“ und der Meldung „Zahlung akzeptiert“ liegen. Durchsatz fragt, wie viel Arbeit das System pro Zeiteinheit erledigt: 1200 Zahlungen pro Sekunde, 40.000 Bestellungen pro Stunde. Beide hängen zusammen, sind aber nicht austauschbar. Ein Reisebus, der 50 Menschen in 100 Minuten von London nach Oxford bringt, hat eine schlechtere Latenz und einen viel besseren Durchsatz als ein Sportwagen, der zwei Menschen in 60 Minuten befördert.
In Software zeigt sich dieselbe Spannung überall. Datenbank-Schreibvorgänge zu bündeln verbessert den Durchsatz, lässt aber jeden einzelnen Schreibvorgang auf seinen Stapel warten. Ein Cache verbessert beides für wiederholte Lesezugriffe, hilft aber nicht beim ersten. Eine gute Performance-Anforderung sagt deshalb, um welche Frage es geht, und nennt meist beides: „bei 1200 Zahlungen pro Sekunde (Durchsatz) werden 99 % innerhalb von 800 ms abgeschlossen (Latenz)“. ISO/IEC 25010 ordnet dies unter Leistungseffizienz als Zeitverhalten, Ressourcennutzung und Kapazität ein (Abschnitt 2.2).
Antwortzeit = Bedienzeit + Wartezeit
Wenn Sie die Latenz auf der Seite des Clients messen, erhalten Sie die Antwortzeit: alles, was zwischen dem Senden der Anfrage und dem Empfang der Antwort geschah. Es lohnt sich, sie in Teile zu zerlegen. Die Bedienzeit ist die Zeit, die eine Ressource tatsächlich an Ihrer Anfrage arbeitet: sie parst, die Abfrage ausführt, das Ergebnis aufbereitet. Die Wartezeit ist die Zeit, die Ihre Anfrage in einer Warteschlange verbringt, weil die Ressource mit der Anfrage eines anderen beschäftigt ist. Hinzu kommt die Netzwerk-Übertragungszeit, in beiden Richtungen.
Die Unterscheidung zählt, weil die beiden Teile auf unterschiedliche Mittel ansprechen. Die Bedienzeit sinkt, wenn Sie die Arbeit selbst billiger machen: ein besserer Index, eine kleinere Nutzlast, ein schnellerer Algorithmus. Die Wartezeit sinkt, wenn Sie Kapazität hinzufügen oder die Last senken, und sie ist bei einem ausgelasteten System oft viel größer als die Bedienzeit. Viele Untersuchungen einer „langsamen Datenbank“ enden mit der Entdeckung, dass jede Abfrage 5 ms dauert, aber 300 ms auf eine freie Verbindung im Pool wartet.
Wohin die Zeit geht
Perzentile: Warum Mittelwerte irreführen
Antwortzeiten sind nie eine einzelne Zahl; sie bilden eine Verteilung, und die ist fast immer schief. Die meisten Anfragen sind schnell, und eine Minderheit ist langsam, weil sie auf einen kalten Cache, eine Garbage-Collection-Pause, eine Sperre, eine Wiederholung oder einen überlasteten Nachbarn trifft. Das arithmetische Mittel vermischt beide Gruppen zu einem Wert, der niemanden beschreibt. Fachleute verwenden stattdessen Perzentile. Das 50. Perzentil (p50, der Median) ist der Wert, den die Hälfte der Anfragen unterbietet; p95 ist der Wert, den 95 % der Anfragen unterbieten; p99 und p99,9 beschreiben die langsamsten 1 % und 0,1 %.
Das langsame Ende der Verteilung heißt Tail, und es ist wichtiger, als es scheint. Die Benutzer im Tail sind oft Ihre besten Kunden: die mit den größten Warenkörben, der längsten Historie und den meisten Daten. Ein Benutzer, der 40 Ressourcen lädt, um eine Seite anzusehen, erlebt die langsamste dieser 40, nicht den Durchschnitt. Und die Wahrscheinlichkeit, dass eine Seite mit 40 Ressourcen mindestens eine p99-Anfrage trifft, beträgt 1 − 0,9940 ≈ 33 %: Ein „seltenes“ 1-%-Ereignis betrifft ein Drittel der Seitenaufrufe.
Ausgearbeitetes Beispiel
Ausgearbeitetes Beispiel: der Mittelwert, der das Problem verbirgt
Eine Produktsuch-API protokolliert in einer Minute 1000 Antwortzeiten: 900 mit 80 ms, 80 mit 150 ms, 15 mit 1200 ms (kalter Cache) und 5 mit 4000 ms (Timeout und Wiederholung).
| Summe aller Zeiten | 900 × 80 + 80 × 150 + 15 × 1200 + 5 × 4000 = 72.000 + 12.000 + 18.000 + 20.000 = 122.000 ms |
|---|---|
| Mittelwert | 122.000 ÷ 1000 = 122 ms. Sieht gegenüber einem Ziel von 200 ms gesund aus. |
| p50 (Median) | Die 500.-schnellste Anfrage: 80 ms |
| p95 | Die 950.-schnellste Anfrage liegt in der 150-ms-Gruppe (Anfragen 901 bis 980): 150 ms |
| p99 | Die 990. liegt in der 1200-ms-Gruppe (Anfragen 981 bis 995): 1200 ms |
| p99.9 | Die 999. liegt in der 4000-ms-Gruppe (996 bis 1000): 4000 ms |
| Wer betroffen ist | 20 von 1000 Anfragen (2 %) dauerten über eine Sekunde. Bei 300 Suchanfragen pro Sekunde sind das 6 Benutzer pro Sekunde oder etwa 21.600 pro Stunde. |
Der Mittelwert von 122 ms besteht ein Ziel von 200 ms, während 2 % der Benutzer länger als eine Sekunde warten. Ein Szenario mit der Formulierung „Durchschnitt unter 200 ms“ würde dieses System durchlassen.
Die Anforderung „p95 ≤ 200 ms und p99 ≤ 500 ms“ lässt es zu Recht durchfallen und lenkt das Team auf die Pfade mit kaltem Cache und Wiederholung.
Perzentile lassen sich nicht mitteln. Das p99 über zehn Server ist nicht der Mittelwert ihrer zehn p99-Werte; es muss aus den zusammengeführten Daten berechnet oder aus zusammengeführten Histogrammen angenähert werden.
# Why the mean misleads: 1,000 response times from one minute of traffic
import statistics
times_ms = [80] * 900 + [150] * 80 + [1200] * 15 + [4000] * 5
mean = statistics.mean(times_ms)
cuts = statistics.quantiles(times_ms, n=1000, method="inclusive")
p50, p95, p99, p999 = cuts[499], cuts[949], cuts[989], cuts[998]
print(f"mean {mean:.0f} ms, p50 {p50:.0f}, p95 {p95:.0f}, p99 {p99:.0f}, p99.9 {p999:.0f}")
# mean 122 ms, p50 80, p95 150, p99 1200, p99.9 4000Tail-Latenz im großen Maßstab
Der Tail wird zum Hauptereignis in großen Systemen mit Fan-out, bei denen eine Benutzeranfrage in viele parallele Anfragen an andere Server aufgeteilt wird und die Antwort auf alle warten muss. Eine Suchmaschine, ein Social-Feed oder eine Empfehlungsseite befragt für jede Abfrage womöglich Dutzende oder Hunderte von Backend-Shards. Jeffrey Dean und Luiz André Barroso von Google haben das in The Tail at Scale (Communications of the ACM, 2013) analysiert.
Ihre Veranschaulichung ist einfach. Angenommen, jeder Server antwortet typischerweise in 10 ms, braucht aber für eine von 100 Anfragen 1 Sekunde. Eine Benutzeranfrage, die auf einen Server wartet, ist in 1 % der Fälle langsam. Eine Benutzeranfrage, die auf 100 solcher Server wartet, ist immer dann langsam, wenn irgendeiner von ihnen langsam ist: in 1 − 0,99100 ≈ 63 % der Fälle. Ein seltenes Ereignis an einem Server wird für den Benutzer zum Normalfall. Dean und Barroso berichten Messungen aus einem Google-Service, bei dem die Latenz im 99. Perzentil für eine einzelne Leaf-Anfrage 10 ms betrug, das 99. Perzentil für das Warten auf alle Leaf-Anfragen aber 140 ms.
Weil sich nicht jede Quelle der Schwankung beseitigen lässt (geteilte Hardware, Hintergrundjobs, Garbage Collection, Netzwerk-Queues), plädieren sie für tail-tolerante Entwürfe, so wie fehlertolerante Entwürfe akzeptieren, dass Hardware ausfällt. Zu ihren Techniken gehören Hedged Requests (eine zweite Kopie an ein anderes Replikat senden, wenn die erste nicht innerhalb etwa der Zeit des 95. Perzentils geantwortet hat, und die zuerst eintreffende Antwort verwenden), verknüpfte Anfragen, die sich gegenseitig abbrechen, feiner granulierte Partitionen, die sich umverteilen lassen, das vorübergehende Ausschließen langsamer Maschinen und die Rückgabe eines ausreichend guten Ergebnisses, wenn die meisten, aber nicht alle Shards geantwortet haben. In einem von ihnen beschriebenen Benchmark senkte Hedging nach 10 ms die Latenz im 99,9. Perzentil von 1800 ms auf 74 ms, bei nur etwa 2 % mehr Anfragen.
Littles Gesetz: wie viele Anfragen gleichzeitig in Bearbeitung sind
Littles Gesetz, 1961 von John Little bewiesen, ist die nützlichste einzelne Formel der Kapazitätsplanung. Für jedes stabile System gilt: Die durchschnittliche Zahl der Elemente darin (L) ist gleich der durchschnittlichen Ankunftsrate (λ, Lambda) multipliziert mit der durchschnittlichen Verweildauer jedes Elements (W): L = λ × W. Es gilt unabhängig vom Ankunftsmuster oder der Reihenfolge der Bedienung, sofern das System stabil ist (im Mittel verlassen es so viele Elemente, wie ankommen) und Sie einheitliche Einheiten verwenden.
In Software ist L die Zahl der gleichzeitig laufenden Anfragen (die Nebenläufigkeit), λ die Anfragerate und W die Antwortzeit. Erhält ein Service 200 Anfragen pro Sekunde und verbringt jede 0,25 Sekunden darin, sind im Mittel jederzeit 200 × 0,25 = 50 Anfragen in Bearbeitung. Diese Zahl bestimmt Thread-Pools, Connection-Pools, Arbeitsspeicher und Lizenzanzahlen. Das Gesetz funktioniert auch rückwärts: Können Sie höchstens 50 Anfragen gleichzeitig halten und dauert jede 0,25 s, schaffen Sie dauerhaft nicht mehr als 50 ÷ 0,25 = 200 Anfragen pro Sekunde.
Ausgearbeitetes Beispiel
Ausgearbeitetes Beispiel: einen Datenbank-Connection-Pool mit Littles Gesetz dimensionieren
Der Fahrtenservice einer Fahrdienst-App verarbeitet zur abendlichen Spitzenzeit 1800 Anfragen pro Sekunde. Jede Anfrage macht Datenbankaufrufe, die eine Verbindung insgesamt 40 ms lang belegen. Jede der 6 Service-Instanzen hat einen Pool von 10 Verbindungen. Reicht das?
| Ankunftsrate λ | 1800 Anfragen pro Sekunde |
|---|---|
| Belegungsdauer einer Verbindung W | 40 ms = 0,040 s |
| Belegte Verbindungen L = λ × W | 1800 × 0,040 = im Mittel 72 belegte Verbindungen |
| Verfügbare Verbindungen | 6 Instanzen × 10 = 60 |
| Ergebnis | 72 > 60. Anfragen werden auf Verbindungen warten, die Wartezeit wächst zur Spitzenzeit unbegrenzt, und die Antwortzeiten steigen, bis Timeouts einsetzen. |
| Ziel mit Kapazitätsreserve | Den Pool höchstens zu etwa 70 % auslasten: 72 ÷ 0,7 ≈ 103 Verbindungen, also etwa 18 pro Instanz |
| Datenbank prüfen | 103 Verbindungen müssen auch für den Datenbankserver tragbar sein; falls nicht, W senken (schnellere Abfragen, weniger Roundtrips) oder die Zahl der Datenbankaufrufe pro Anfrage verringern |
| Was, wenn die Abfragen schneller werden? | Wird W auf 25 ms gesenkt, ergibt sich L = 1800 × 0,025 = 45 Verbindungen; das passt bei 75 % Auslastung in die vorhandenen 60 |
Littles Gesetz rechnet ein Durchsatzziel und eine Latenz in eine Nebenläufigkeitszahl um, die sich direkt mit einem konfigurierten Limit vergleichen lässt.
Es liefert Mittelwerte. Lastspitzen treiben die momentane Zahl höher; deshalb plant das Beispiel eine Reserve ein, statt genau auf 72 zu dimensionieren.
Auslastung und Warteschlangen: Warum Systeme von der Klippe stürzen
Auslastung (ρ, Rho) ist der Anteil der Zeit, in dem eine Ressource belegt ist. Ein Server, der 40 Anfragen pro Sekunde erhält, die jeweils 20 ms Bedienzeit brauchen, ist 40 × 0,020 = 0,8 der Zeit belegt: zu 80 % ausgelastet. Die Intuition sagt, eine zu 80 % belegte Ressource sollte nur wenig langsamer sein als eine zu 50 % belegte. Die Theorie der Warteschlangenbildung sagt etwas anderes, denn Anfragen treffen nicht gleichmäßig ein; sie ballen sich, und wenn sie sich ballen, warten die späteren.
Das einfachste Modell ist die M/M/1-Warteschlange: zufällige Ankünfte, zufällige Bedienzeiten und ein einzelner Server. Ihre mittlere Antwortzeit ist W = S ÷ (1 − ρ), wobei S die mittlere Bedienzeit ist. Bei 50 % Auslastung ist W = 2S. Bei 80 % ist W = 5S. Bei 90 % ist W = 10S. Bei 99 % ist W = 100S. Der Nenner schrumpft gegen null, wenn sich die Auslastung 100 % nähert, sodass die Antwortzeit unbegrenzt wächst. Reale Systeme sind nicht genau M/M/1, und Pools mit mehreren Servern verhalten sich bei gleicher Auslastung besser, aber die Form ist universell: flach, dann ein Knick, dann eine Klippe.
M/M/1-Warteschlange: mittlere Antwortzeit bei 20 ms Bedienzeit
| Auslastung ρ | W = S ÷ (1 − ρ) | Mittlere Antwortzeit | Davon Wartezeit |
|---|---|---|---|
| 50% | 20 ÷ 0.5 | 40 ms | 20 ms |
| 70% | 20 ÷ 0.3 | 67 ms | 47 ms |
| 80% | 20 ÷ 0.2 | 100 ms | 80 ms |
| 90% | 20 ÷ 0.1 | 200 ms | 180 ms |
| 95% | 20 ÷ 0.05 | 400 ms | 380 ms |
| 99% | 20 ÷ 0.01 | 2000 ms | 1980 ms |
Die Auslastungsklippe
Die praktischen Lehren sind direkt. Planen Sie nicht, kritische Ressourcen nahe 100 % Belegung zu betreiben; lassen Sie Reserve, damit Lastspitzen Sie nicht über den Knick schieben. Beobachten Sie Auslastung und Queue-Länge gemeinsam (die USE-Methode von Brendan Gregg prüft für jede Ressource Auslastung, Sättigung und Fehler). Und denken Sie daran, dass die Klippe kleine Änderungen gefährlich macht: Bei 90 % Auslastung bringt Sie ein Anstieg des Traffics um nur etwa 6 % auf 95 % und verdoppelt die mittlere Antwortzeit. Kapitel 9 behandelt Queues, Backpressure und Kapazitätsplanung in Asynchronität, Queues und Backpressure.
Skalierbarkeit: Last, Elastizität, Scale-up und Scale-out
Skalierbarkeit ist die Fähigkeit, durch zusätzliche Ressourcen mehr Last zu bewältigen, idealerweise mit proportional wachsender Kapazität und ohne Neuentwurf. Sie bedeutet erst etwas, wenn Sie sagen, was „Last“ ist. Lastparameter unterscheiden sich von System zu System: Anfragen pro Sekunde bei einer API, gleichzeitige Verbindungen bei einem Chatdienst, das Verhältnis von Lese- zu Schreibzugriffen bei einem sozialen Netzwerk, das Datenvolumen bei einer Analyseplattform oder die Zahl der Follower des meistgefolgten Kontos bei einem Feed. Ein Skalierbarkeitsszenario nennt den Lastparameter, das Wachstum und die Antwort, die erhalten bleiben muss: „Wenn die täglichen Bestellungen von 50.000 auf 500.000 steigen, bleibt die p95-Latenz des Checkouts durch zusätzliche Instanzen unter 1,5 s, bei höchstens 20 % höheren Kosten pro Bestellung.“
Elastizität fügt die Zeit hinzu: die Fähigkeit, Kapazität automatisch hinzuzufügen und zu entfernen, wenn die Last steigt und fällt, sodass eine Ticketplattform für einen Vorverkauf wachsen und danach wieder schrumpfen kann. Sie ist ein großer Teil des wirtschaftlichen Arguments für Cloud-Plattformen. Es gibt zwei grundlegende Wege, Kapazität hinzuzufügen. Vertikale Skalierung (Scale-up) gibt einem Rechner mehr CPU, mehr Arbeitsspeicher oder schnelleren Speicher; sie ist einfach, erfordert keine Änderung an der Software und stößt an harte Grenzen und steigende Preise. Horizontale Skalierung (Scale-out) fügt weitere Rechner hinzu und verteilt die Arbeit; sie hat keine feste Obergrenze, verlangt aber, dass die Software dafür entworfen ist, mit zustandslosen Instanzen, Lastverteilung und partitionierten Daten. Kapitel 9 behandelt die Strategien ausführlich in Skalierungsstrategien: vertikal, horizontal und der Scale Cube.
Amdahls Gesetz: die Grenze der Parallelität
Mehr Prozessoren oder Knoten helfen nur bei Arbeit, die sich parallel erledigen lässt. Das Amdahlsche Gesetz, aus Gene Amdahls Aufsatz von 1967 über die Grenzen des parallelen Rechnens, erfasst das. Ist ein Anteil s der Arbeit seriell (er muss Schritt für Schritt erledigt werden) und lässt sich der Rest, 1 − s, perfekt auf N Prozessoren aufteilen, beträgt die bestmögliche Beschleunigung speed-up(N) = 1 ÷ (s + (1 − s) ÷ N). Wächst N unbegrenzt, nähert sich die Beschleunigung 1 ÷ s. Bei 10 % serieller Arbeit kann keine Zahl von Prozessoren den Job mehr als zehnmal schneller machen.
Ausgearbeitetes Beispiel
Ausgearbeitetes Beispiel: ein nächtlicher Abrechnungslauf
Der nächtliche Abrechnungslauf eines Telekommunikationsunternehmens dauert auf einem Server 8 Stunden. Profiling zeigt, dass 10 % der Zeit seriell sind (Tarife laden, dann eine einzige Zusammenfassungsdatei schreiben); die anderen 90 % bewerten Anrufe unabhängig pro Kunde. Der Lauf muss in unter 1,5 Stunden fertig sein. Wie viele Server werden gebraucht?
| Serieller Anteil s | 0,10; paralleler Anteil 0,90 |
|---|---|
| Benötigte Beschleunigung | 8 h ÷ 1.5 h ≈ 5.33 |
| N = 4 | 1 ÷ (0,10 + 0,90 ÷ 4) = 1 ÷ 0,325 ≈ 3,08; Laufzeit 8 ÷ 3,08 ≈ 2,6 h |
| N = 8 | 1 ÷ (0,10 + 0,1125) = 1 ÷ 0,2125 ≈ 4,71; Laufzeit ≈ 1,70 h |
| N = 16 | 1 ÷ (0,10 + 0,05625) = 1 ÷ 0,15625 = 6,4; Laufzeit = 1,25 h |
| Kleinstes N, das das Ziel erreicht | Nötig ist 0,10 + 0,90 ÷ N ≤ 1 ÷ 5,33 = 0,1875, also N ≥ 0,90 ÷ 0,0875 ≈ 10,3: 11 Server ergeben 1 ÷ (0,10 + 0,0818) ≈ 5,50, Laufzeit ≈ 1,45 h |
| N = 64 | 1 ÷ (0,10 + 0,0141) ≈ 8,77; Laufzeit ≈ 0,91 h |
| Grenzwert für wachsendes N | 1 ÷ 0,10 = 10; Laufzeit nie unter 0,8 h |
| Alternative | Den seriellen Teil halbieren (s = 0,05), etwa indem die Tarife parallel geladen werden. Dann ergeben 8 Server 1 ÷ (0,05 + 0,11875) ≈ 5,93, Laufzeit ≈ 1,35 h: Das Ziel wird mit 8 statt 11 Servern erreicht. |
Der Schritt von 16 auf 64 Server (die vierfachen Kosten) verkürzt den Lauf nur von 1,25 h auf 0,91 h. Der Ertrag nimmt schnell ab.
Den seriellen Anteil zu verringern ist oft weit billiger, als Hardware hinzuzufügen. Architekten suchen nach den versteckten seriellen Teilen: einer einzelnen Sperre, einer Datenbankzeile, die alle aktualisieren, einem zentralen Koordinator.
Das Universal Scalability Law
Amdahls Gesetz nimmt an, dass zusätzliche Prozessoren die Lage nie verschlechtern; die Beschleunigung flacht nur ab. Reale verteilte Systeme werden oft tatsächlich schlechter: Ab einem gewissen Punkt senken weitere Knoten den Durchsatz. Neil Gunthers Universal Scalability Law (USL) modelliert das mit zwei Abzügen. Konkurrenz (α, Alpha) sind die Kosten des Wartens auf geteilte Ressourcen, derselbe Effekt wie Amdahls serieller Anteil. Kohärenz (β, Beta) sind die Kosten, Daten zwischen Knoten konsistent zu halten: Jeder Knoten muss mit jedem anderen Informationen austauschen, sodass diese Kosten ungefähr mit dem Quadrat der Knotenzahl wachsen.
Die relative Kapazität ist C(N) = N ÷ (1 + α(N − 1) + βN(N − 1)). Mit β = 0 reduziert sie sich auf Amdahls Gesetz. Mit jedem β über null erreicht die Kapazität bei etwa N = √((1 − α) ÷ β) einen Höchstwert und fällt dann. Für α = 0,03 und β = 0,002 liegt der Höchstwert bei etwa √(0,97 ÷ 0,002) ≈ 22 Knoten, mit einer Kapazität von etwa dem 8,6-Fachen eines Knotens; bei 32 Knoten ist die Kapazität wieder auf etwa 8,2 gesunken. Gunther beschreibt das Modell in Guerrilla Capacity Planning (2007). Sein praktischer Wert liegt darin, dass sich α und β an eine Handvoll Lasttest-Messungen anpassen lassen, sodass Sie vorhersagen können, wo sich Skalierung nicht mehr lohnt, bevor Sie die Hardware kaufen.
Lineare, Amdahl- und USL-Skalierung
Taktiken für Performance: ein Überblick
Bass, Clements und Kazman ordnen Performance-Taktiken in zwei Familien. Die erste ist, den Ressourcenbedarf zu steuern: zu verringern, wie viel Arbeit ankommt oder wie viel jede Einheit kostet. Die zweite ist, Ressourcen zu verwalten: die verfügbaren Ressourcen stärker zu nutzen oder mehr davon hinzuzufügen. Die meisten realen Entwürfe kombinieren mehrere Taktiken; jede hat auch anderswo Kosten, weshalb es sich um Architekturentscheidungen handelt.
Performance-Taktiken und wo der Kurs sie behandelt
| Taktik | Was er tut | Typische Kosten oder Risiken | Mehr dazu in |
|---|---|---|---|
| Bedarf verringern: Rate Limiting, Zugangskontrolle, Warteräume | Begrenzt oder glättet die eingehende Last, sodass der Kern unterhalb seines Knicks bleibt | Manche Benutzer werden verzögert oder abgewiesen | Kapitel 9: Queues und Backpressure |
| Arbeit pro Anfrage verringern: effiziente Algorithmen, kleinere Nutzlasten, weniger Roundtrips | Senkt die Bedienzeit | Entwicklungsaufwand; manchmal weniger flexibler Code | Kapitel 0: Daten und Algorithmen |
| Priorisieren und einplanen | Bedient wichtige Arbeit zuerst (bezahlte Bestellungen vor Berichten) | Niedrig priorisierte Arbeit kann verhungern | Kapitel 9: Resilienzmuster |
| Caching | Hält Ergebnisse nahe beim Benutzer, um wiederholte Arbeit zu vermeiden | Veraltete Daten, aufwendige Invalidierung, Speicherkosten | Kapitel 7: Caching |
| Nebenläufigkeit und Asynchronität | Verarbeitet unabhängige Arbeit parallel; nimmt langsame Arbeit aus dem Anfragepfad | Schwierigeres Nachvollziehen, Probleme mit Reihenfolge und Konsistenz | Kapitel 6: Kommunikation |
| Replikation | Fügt Kopien von Services oder Daten hinzu, um Lesezugriffe und Last zu verteilen | Konsistenz zwischen den Kopien; Kosten | Kapitel 7: Replikation und Partitionierung |
| Partitionierung (Sharding) | Teilt Daten und Arbeit auf, sodass jeder Knoten einen Anteil übernimmt | Partitionsübergreifende Abfragen und Umverteilung sind schwierig | Kapitel 7: Replikation und Partitionierung |
| Ressourcen hinzufügen: Scale-up oder Scale-out | Erhöht die Kapazität | Kosten; begrenzt durch serielle Arbeit und Kohärenzaufwand | Kapitel 9: Skalierungsstrategien |
Prüfen Sie Ihr Verständnis
Ein Service erhält 500 Anfragen pro Sekunde, und jede dauert 80 ms. Wie viele sind im Mittel gleichzeitig in Bearbeitung?
Nach Littles Gesetz ist L = 500 × 0,08 = 40 Anfragen in Bearbeitung.
Wie hoch ist nach der M/M/1-Formel die mittlere Antwortzeit eines Servers mit 10 ms Bedienzeit bei 75 % Auslastung?
W = 10 ÷ (1 − 0,75) = 40 ms, davon 30 ms Wartezeit.
Warum ist p99 als Anforderungsmaß meist besser als der Mittelwert?
Verteilungen von Antwortzeiten sind schief; der Mittelwert kann gesund aussehen, während ein nennenswerter Teil der Benutzer sehr langsame Antworten erleidet, und p99 macht diesen Tail sichtbar.
Wenn 20 % eines Jobs seriell sind, wie groß ist die maximale Beschleunigung durch zusätzliche Prozessoren?
1 ÷ 0,2 = das 5-Fache, egal wie viele Prozessoren hinzukommen.
Quellen und weiterführende Literatur
Haben Sie eine Frage zu diesem Abschnitt? ArchitectBot, der KI-Lernassistent des Kurses, antwortet zuerst aus dem Kurs.
Fragen: „Unsere API braucht im Durchschnitt 150 ms, aber Benutzer beschweren sich trotzdem, dass sie langsam ist. Wie sollte ich ihre Performance messen und Ziele dafür festlegen?“