Der ungenutzte Rabatt: Warum Spot und Graviton so günstig sind
Die AWS-Rechnung lag zwei Monate in Folge über dem Budget. Auf der Suche nach Ressourcen zum Einsparen zeigte sich: Der eigentliche Hebel war nicht 'wie viel man nutzt', sondern 'wie man einkauft'. Warum Spot und Graviton so günstig sind, und warum manche Posten wie Verschwendung aussehen, aber nicht abgeschaltet werden dürfen (RDS Proxy) - eine Geschichte über das 'Warum' hinter jeder Zahl auf der Rechnung.
Das Wichtigste
Wenn es heißt, die Cloud-Kosten zu senken, greift man reflexartig zum Rotstift. Sind die Ressourcen aber bereits optimiert, bleibt als Hebel nur noch die Art des Einkaufs. Fargate Spot verkauft überschüssige AWS-Kapazität mit der Bedingung, sie innerhalb von 2 Minuten wieder freizugeben - deshalb 70% günstiger (und wegen der Bedingung nur für staging geeignet). Graviton ist ein von AWS selbst entworfener ARM-Chip ohne Zwischenmarge, deshalb 20% günstiger (und ohne Bedingung, also auch für die Produktion). Umgekehrt gibt es Posten wie RDS Proxy, die wie Verschwendung aussehen, aber tatsächlich eine Versicherung gegen Connection-Spitzen sind. Eine Rechnung zu lesen heißt nicht, Zahlen zu verkleinern, sondern den Grund hinter jeder Zahl zu verstehen - Rabatte mit vertretbaren Bedingungen mitnehmen, Kosten, die Ausfälle verhindern, stehen lassen.
Auf dieser Seite
Die AWS-Rechnung lag zwei Monate hintereinander über dem Budget, jeweils um einen einstelligen Prozentsatz - in absoluten Zahlen nicht viel, aber die Richtung stimmte nicht. Also ging ich Ressource für Ressource durch, auf der Suche nach etwas zum Kürzen - und kam zu einem überraschenden Schluss. Es gab kaum noch etwas zu kürzen. Der eigentliche Hebel lag nicht darin, wie viel man nutzt, sondern wie man einkauft. Dabei wurde klar: Hinter jeder Zahl auf der Rechnung steckt ein Grund, und nur wer diesen Grund kennt, kann entscheiden, was man abschaltet und was man behält.
Die Ressourcen waren bereits durchoptimiert
Zuerst schaute ich mir den Verbrauch selbst an. Doch hier war schon viel Arbeit hineingeflossen. Das NAT-Gateway war bereits entfernt und durch ein Design mit öffentlichen Subnetzen ersetzt, Logs wurden nur 7 Tage aufbewahrt, Tracing lief mit 1% Sampling, und das Monitoring-Dashboard war ins kostenlose Kontingent gequetscht. DB und Redis liefen bereits auf den günstigeren ARM-Instanzen, S3 nutzte automatisches Tiering, und der Bastion-Host wurde nur bei Bedarf gestartet. Auf der Ressourcenebene war praktisch schon alles ausgereizt, was sich ausreizen ließ.
Die Juni-Rechnung sah nach Posten aufgeschlüsselt so aus: Der größte Posten war mit Abstand die DB (RDS) mit rund 40% der Gesamtsumme allein, gefolgt von Compute (ECS Fargate) mit rund 17%, Load Balancer und WAF mit jeweils rund 10%, während öffentliche IP, Cache (ElastiCache) und S3 nur noch mit einstelligen Prozentanteilen zu Buche schlugen. Die Instanzen hier noch kleiner zu machen, wäre ein Rückschritt gewesen. Die DB war schon einmal wegen Speichermangels hochskaliert worden, und die WAF war bewusst eingerichtet, um Regeln vor dem Produktions-Deployment zu prüfen. Der verbleibende Hebel war also nicht die Ressource, sondern die Art des Einkaufs - dieselben Ressourcen behalten, aber günstiger einkaufen.
Warum Spot so günstig ist
Als Erstes fiel auf, dass Compute ausschließlich zum vollen On-Demand-Preis eingekauft wurde. Dabei gibt es bei AWS einen Kanal, über den derselbe Server deutlich günstiger zu haben ist: Fargate Spot. Rund 70% günstiger als On-Demand.
Dass es so billig ist, hat einen Grund. AWS baut seine Rechenzentren für die Spitzenlast aus. Im Normalbetrieb bleiben also Server übrig. Ungenutzte Kapazität bringt keinen Umsatz, also verkauft AWS diese Restkapazität zum Schleuderpreis - mit der Bedingung, dass sie einem zahlenden On-Demand-Kunden innerhalb von 2 Minuten weichen muss. Das Prinzip ist dasselbe wie bei einer Fluggesellschaft, die kurz vor dem Abflug leere Sitze verramscht: Startet das Flugzeug ohnehin leer, ist der Umsatz null, also lohnt es sich, sie notfalls mit Bedingungen zu verkaufen.
Entscheidend ist, ob man diese Bedingung - "wenn verlangt, weicht man" - verkraften kann. In der Produktion ist das schwierig. Wenn Nutzer aktiv verbunden sind und der Task nach 2 Minuten zurückgefordert wird, gerät der Service zumindest kurz ins Wanken. Bei staging sieht das anders aus. Dort gibt es keine echten Nutzer, und selbst ein paar Minuten Ausfall stören höchstens kurz eine einzelne QA-Person. Also wurde die API von staging auf Spot umgestellt. Die Performance ist dabei völlig identisch zu On-Demand, da vCPU und Speicher auf derselben Hardware laufen. Der einzige Unterschied ist die Verfügbarkeitsbedingung - dass der Task zurückgefordert werden kann -, und genau diese Bedingung nimmt staging bereitwillig in Kauf. Nach der Umstellung liefen die staging-Tasks problemlos auf Spot.
Warum Graviton so günstig ist
Der zweite Punkt war der Chip. DB und Redis liefen bereits auf ARM-Instanzen, ausgerechnet Fargate - wo die Anwendung selbst läuft - war jedoch noch auf x86 geblieben. Wechselt man zu Graviton, dem eigenen ARM-Chip von AWS, bekommt man dieselbe Leistung rund 20% günstiger.
Der Grund für den niedrigen Preis unterscheidet sich von dem bei Spot. Bei gewöhnlichen Instanzen kauft AWS die CPUs von Intel oder AMD ein, sodass im Preis, den wir zahlen, die Marge des Chipherstellers steckt. Graviton ist ein Chip, den AWS selbst entwirft - diese Zwischenmarge entfällt also. Hinzu kommt, dass die ARM-Architektur bei gleicher Rechenleistung weniger Strom verbraucht und weniger Wärme erzeugt, was auch die Strom- und Kühlkosten im Rechenzentrum senkt. Da die eigenen Kosten für AWS niedriger sind, bleibt selbst bei 20% günstigerem Verkauf noch Marge übrig - und zugleich ist es eine Strategie, um Kunden über den niedrigen Preis in das eigene Chip-Ökosystem zu ziehen.
Hier liegt der entscheidende Unterschied. Der Spot-Rabatt kommt mit der Bedingung "akzeptiere die Rückforderung", der Graviton-Rabatt dagegen ist bedingungslos - es ist schlicht ein günstigerer Chip. Während Spot also nur in staging einsetzbar ist, lässt sich Graviton unverändert bis in die Produktion übernehmen. Auch bei der Performance gibt es kaum Grund zur Sorge. Bei Node.js ist die Leistung pro vCPU auf Graviton mit x86 gleichwertig oder sogar besser. Der einzige Punkt, den man beobachten sollte, ist der Kaltstart: Beim ersten Start der App kommt es auf die Single-Core-Geschwindigkeit an, und hier kann Graviton etwas langsamer sein als aktuelles x86, wodurch der Start ein paar Sekunden länger dauert. Deshalb wurde zuerst in staging die Startzeit gemessen, bevor die Umstellung in die Produktion erfolgte. Als Vorabprüfung reicht es, zu kontrollieren, ob die nativen Module für arm64 gebaut werden.
Fasst man den Charakter der beiden Rabatte zusammen: Spot ist ein Rabatt als Gegenleistung für die Unannehmlichkeit, daher die Bedingung (deshalb nur staging), Graviton ist ein Rabatt, bei dem man am Kostenvorteil von AWS' eigenem Chip teilhat, daher ohne Bedingung (deshalb bis in die Produktion). Bei gleicher Leistung gab es keinen Grund, weiter auf dem teureren x86-Listenpreis zu bleiben. Diese Optimierung war eigentlich weniger neues Sparen als vielmehr, endlich einen Rabatt in Anspruch zu nehmen, den man bislang nicht genutzt hatte.
Manche Kosten darf man nicht abschalten
Beim Durchgehen der Rechnung gibt es aber auch eine Falle in die andere Richtung: Posten, die wie Verschwendung aussehen, aber tatsächlich eine Versicherung sind.
RDS Proxy war so ein Fall. Monatlich fielen feste Kosten an, und zunächst sah es nach einem Kandidaten zum Einsparen aus. Eine der Funktionen von Proxy ist die unterbrechungsfreie automatische Secret-Rotation - und diese Rotation war gerade deaktiviert. Wozu also einen Proxy behalten, wenn die Rotation gar nicht genutzt wird, dachte ich.
Das war ein Missverständnis. Der eigentliche Zweck von Proxy ist nicht die Rotation, sondern die Abwehr von Connection-Spitzen. Wenn bei einem Deployment oder Scale-out plötzlich mehr Tasks entstehen, schnellen die Verbindungen zur DB nach oben - die DB hat aber ein Limit für gleichzeitige Verbindungen. Proxy bündelt und multiplext die Verbindungen davor, sodass dieses Limit nicht überschritten wird. Ausgerechnet diese DB war eine Instanz, die schon einmal wegen Speichermangels hochskaliert worden war, und jede einzelne Verbindung verbraucht Speicher. Diese festen Kosten waren also keine Verschwendung, sondern die Versicherungsprämie dafür, dass die DB bei jedem Deployment nicht durch eine Verbindungsflut zusammenbricht. Sie abzuschalten hätte nicht gespart, sondern die Schutzmauer eingerissen.
Ursache des Missverständnisses war der Code-Kommentar. Der Kommentar zu diesem Proxy war überwiegend aus Sicht der Rotation geschrieben, sodass man leicht zu dem Trugschluss kam: "Rotation ist deaktiviert, also braucht man auch keinen Proxy." Statt Proxy also aus dem Sparplan zu streichen, wurde dem Kommentar eine Zeile hinzugefügt: "Hauptzweck ist die Abwehr von Connection-Spitzen, Rotation ist nur eine Zusatzfunktion." Damit die nächste Person, die die Rechnung liest, nicht denselben Fehlschluss zieht.
Hinter jeder Zahl auf der Rechnung steckt ein Grund
Hört man "Cloud-Kosten senken", greift die Hand reflexartig danach, etwas abzuschalten. Instanzen verkleinern, Funktionen deaktivieren, Ressourcen löschen. Was ich dieses Mal gelernt habe, war das Gegenteil. Bevor man kürzt, muss man fragen: "Warum steht diese Zahl überhaupt hier?"
Manche Zahlen sind ein nicht genutzter Rabatt. Wie bei Spot und Graviton gibt es einen Kanal, um dieselbe Ressource günstiger einzukaufen, man hat aber einfach zum vollen Preis gekauft. Jeder dieser Rabatte hat seinen eigenen Grund, günstig zu sein, und wer diesen Grund kennt - Rückforderung akzeptieren oder bedingungsloser Kostenvorteil -, weiß, wo er sich gefahrlos anwenden lässt. Andere Zahlen sind umgekehrt eine Versicherung, die man nicht abschalten darf. Sieht ein Posten nach Verschwendung aus, verhindert aber tatsächlich einen Vorfall, dann ist dieser Posten keine Ausgabe, sondern eine Verteidigung.
Am Ende bedeutet eine Rechnung zu lesen nicht, Zahlen kleiner zu machen, sondern den Grund jeder einzelnen Zahl zu verstehen. Kennt man den Grund, nimmt man Rabatte mit vertretbaren Bedingungen mit und lässt Kosten stehen, die Vorfälle verhindern. Genau das war alles, was wir getan haben. Nicht neu gespart, sondern nur unterschieden, welchen Rabatt man in Anspruch nehmen sollte und welche Versicherung man behalten muss.
Häufige Fragen
Kann man Fargate Spot auch in der Produktion einsetzen?
Der Kompromiss bei Spot ist, dass ein Task nach einer 2-minütigen Vorwarnung zurückgefordert werden kann. Wenn eine Umgebung diese Unterbrechung verkraftet, lässt sich Spot auch in der Produktion nutzen. Bei einer HA-Konfiguration mit mehreren Tasks, bei der eine Kapazitätsreduzierung von wenigen Minuten nicht kritisch ist, ist auch ein teilweiser Einsatz möglich. Bei einem einzelnen Task oder bei Workloads, die empfindlich auf Unterbrechungen reagieren, ist das jedoch riskant - dann beginnt man sicherheitshalber mit staging, wo eine Unterbrechung folgenlos bleibt.
Sinkt die Performance, wenn man auf Graviton (ARM) umsteigt?
Bei den meisten Workloads ist sie gleichwertig oder sogar besser. Besonders bei Node.js ist die Performance pro vCPU auf Graviton mit x86 vergleichbar. Der einzige Punkt, den man im Auge behalten sollte, ist der Kaltstart: Beim ersten Hochfahren der App ist die Single-Core-Geschwindigkeit etwas langsamer als bei aktuellem x86, wodurch der Start ein paar Sekunden länger dauern kann. Man misst die Startzeit zunächst in staging und geht erst danach in die Produktion über - vorab muss man nur prüfen, ob die nativen Module für arm64 gebaut werden.
Ähnliche Beiträge
- 💻 Entwicklung
Self-Hosting auf dem Mini-PC mit Docker + Cloudflare Tunnel
Wie man mit einem einzigen Mini-PC zu Hause mehrere Webdienste sicher öffentlich macht. HTTPS ohne offene Ports über Cloudflare Tunnel, betrieben mit Docker Compose.
- 💻 Entwicklung
Der Shutdown-Hook lief zweimal - als SIGTERM zwei Herren hatte
Bei jedem Deploy landete ein Prisma-P2028-Fehler in Sentry. Ich wollte nur die Shutdown-Reihenfolge korrigieren, fand dabei aber heraus, dass enableShutdownHooks von NestJS und eine graceful-shutdown-Bibliothek beide auf SIGTERM lauschten - und die Shutdown-Hooks deshalb bei jedem Neustart doppelt liefen.
- 💻 Entwicklung
Schalt's doch einfach in Staging ab - der laute Alarm, der den eigentlichen Bug verdeckte
In Staging kam jeden Tag derselbe Google-Play-404-Alarm. Schaltet man die Quelle ab, wird es still - aber das ist etwas anderes, als den Fehlermodus tatsächlich zu beheben. Ein 404 ist ein dauerhafter Fehler, den kein Retry behebt, und trotzdem wurde er mit 5xx in einen Topf geworfen und erneut versucht.