Hallo zusammen, hier ist Jules Martin, zurück auf agntmax.com!
Heute möchte ich über etwas sprechen, das mich und wahrscheinlich viele von euch seit etwa einem Jahr beschäftigt: den schrittweisen Anstieg der Kosten für Cloud-Infrastruktur, insbesondere wenn es um serverlose Funktionen geht. Wir alle wurden von dem Traum „bezahle nur für das, was du nutzt“ verführt, und lange Zeit schien das eine Realität zu sein. Aber in letzter Zeit habe ich die Rechnungen steigen sehen, manchmal auf unverständlich hohe Werte, selbst wenn die Nutzungsmuster stabil schienen. Es ist, als würden wir von der Flexibilität, die wir angenommen haben, aufgefressen. Lassen Sie uns also etwas sehr Konkretes und Aktuelles erkunden: Den Serverlosen Monster Bezwingen: Verborgene Kosten von AWS Lambda Aufdecken und Reduzieren.
Mein eigener Weg in diesem Bereich begann vor etwa sechs Monaten. Wir haben einen zentralen Mikrodienst, der die Benutzerauthentifizierung und das Management von Sitzungen übernimmt. Er ist fast vollständig auf AWS Lambda, API Gateway, DynamoDB und Cognito aufgebaut. Lange Zeit waren die Kosten perfekt vorhersehbar. Dann sprang im letzten Sommer unsere AWS-Rechnung für diesen speziellen Dienst um etwa 15 %. Keine neuen Funktionen, keine signifikanten Verkehrsspitzen. Zunächst dachte ich, das sei auf saisonale Schwankungen oder einen kleinen Bug zurückzuführen, den ich noch nicht entdeckt hatte. Aber als die Rechnung des nächsten Monats noch höher war, wusste ich, dass ich nachforschen musste. Es war kein Einzelfall; es war ein Trend, und es kostete uns tatsächlich Geld.
Die Illusion der „Kostenlosen“ Stufen und die Realität der „Minimalen“ Aufrufe
Eines der Hauptverkaufsargumente für serverlose Lösungen, insbesondere für Startups oder kleine Teams, ist das großzügige kostenlose Kontingent. Und es ist großzügig! Eine Million kostenlose Aufrufe pro Monat für Lambda, plus eine signifikante Menge an Rechenzeit. Das Problem ist, dass diese “kostenlosen” Aufrufe verschwinden, je größer Ihre Anwendung wird, schneller als ein Stück Pizza bei einem Tech-Meetup. Oft wird das erhebliche Volumen der scheinbar unbedeutenden minimalen Aufrufe, die sich ansammeln, übersehen. Denken Sie an Cron-Jobs, interne Gesundheitsprüfungen oder sogar Retry-Mechanismen anderer Dienste. Jede dieser Aufrufe zählt.
Meine Untersuchung unseres Authentifizierungsdienstes enthüllte genau das. Wir hatten eine Lambda-Funktion, nennen wir sie auth-token-refresher, die regelmäßig die internen Servicetokens aktualisieren sollte. Sie war so konzipiert, dass sie alle fünf Minuten ausgeführt wird. Das klingt harmlos, oder? 288 Aufrufe pro Tag. Multiplizieren Sie das mit 30 Tagen, und Sie erhalten 8.640 Aufrufe pro Monat. Fügen Sie unsere Entwicklungs-, Staging- und Produktionsumgebungen hinzu, und auf einmal sind das über 25.000 Aufrufe nur für eine kleine Wartungsaufgabe. Wir hatten ein Dutzend solcher Funktionen. Plötzlich waren unsere „minimale“ Aufrufe nicht mehr so minimal.
Die Übeltäter Finden: CloudWatch-Metriken Sind Ihre Besten Freunde
Der erste Schritt, um dieses Biest zu bändigen, ist zu wissen, wohin Ihr Geld fließt. AWS CloudWatch ist dabei unerlässlich. Schauen Sie sich nicht nur das Dashboard mit den Gesamtrechnungen an; erkunden Sie die spezifischen Metriken für Ihre Lambda-Funktionen.
Hier konzentrierte ich mich:
- Aufrufe: Dies ist die einfachste Metrik. Hohe Aufrufzahlen für Funktionen, die keinen direkten Benutzerverkehr verarbeiten, sind sofortige Warnsignale.
- Dauer: Wie lange läuft jeder Aufruf? Längere Zeiten bedeuten höhere Berechnungskosten.
- Speicherverbrauch: Haben Sie zu viel Speicher für Ihre Funktionen bereitgestellt? Sie bezahlen für das, was Sie zuweisen, nicht für das, was Sie tatsächlich nutzen.
- Fehlerquote: Hohe Fehlerquoten können zu Wiederholungen führen, was mehr Aufrufe und verschwendete Berechnungszyklen bedeutet.
Für unseren auth-token-refresher habe ich mir die Metrik `Aufrufe` genauer angesehen. Tatsächlich lief sie wie ein Uhrwerk, alle fünf Minuten. Die Dauer war minimal, nur etwa 50ms. Aber das erhebliche Volumen trug zu unseren Gesamtkosten für Aufrufe bei.
Praxiste Beispiel 1: Konsolidieren und Intelligenter Planen
Die Lösung für auth-token-refresher und mehrere andere ähnliche Wartungsfunktionen war erstaunlich einfach: die Konsolidierung. Statt individuelle Lambda-Funktionen zu haben, die durch CloudWatch-Ereignisse (oder heutzutage EventBridge) zu unterschiedlichen Zeiten ausgelöst werden, habe ich eine einzige Lambda-Funktion namens „Maintenance Runner“ erstellt.
Dieser „Maintenance Runner“ wird durch eine einzige CloudWatch-Ereignisregel ausgelöst, sagen wir, einmal pro Stunde. Innerhalb dieses Runners habe ich einen einfachen Dispatcher, der die aktuelle Uhrzeit überprüft und die erforderlichen Aufgaben ausführt. Zum Beispiel:
import os
import datetime
def lambda_handler(event, context):
current_hour = datetime.datetime.now().hour
current_minute = datetime.datetime.now().minute
# Aufgabe 1: Authentifizierungstoken aktualisieren (lief früher alle 5 Min)
if current_minute % 10 == 0: # Jetzt alle 10 Minuten ausführen
print("Führe Aktualisierung des Authentifizierungstokens aus...")
# Rufe die eigentliche Logik zur Aktualisierung des Tokens oder eine andere interne Funktion auf
refresh_auth_token()
# Aufgabe 2: Alte Logs bereinigen (lief früher jede Stunde)
if current_hour % 1 == 0 and current_minute == 0: # Zu Beginn der Stunde ausführen
print("Führe Bereinigung der Logs aus...")
cleanup_old_logs()
# Aufgabe 3: Status des externen Dienstes überprüfen (lief früher alle 30 Min)
if current_minute == 0 or current_minute == 30:
print("Überprüfe den Status des externen Dienstes...")
check_external_service()
return {
'statusCode': 200,
'body': 'Wartungsaufgaben ausgeführt.'
}
def refresh_auth_token():
# ... tatsächliche Logik zur Aktualisierung des Tokens ...
pass
def cleanup_old_logs():
# ... tatsächliche Logik zur Bereinigung der Logs ...
pass
def check_external_service():
# ... tatsächliche Logik zur Überprüfung des externen Dienstes ...
pass
Diese einfache Änderung hat sofort die Anzahl der Aufrufe für diese Wartungsaufgaben von Hunderttausenden pro Monat auf einige Tausend reduziert. Die Einsparungen waren spürbar, nicht nur in Bezug auf Lambda-Aufrufe, sondern auch hinsichtlich des Loggings von CloudWatch und der API Gateway-Aufrufe (wenn einer dieser Aufrufe über API Gateway exponiert war).
Die Falle der Überprovisionierung von Speicher
Das stellt einen weiteren subtilen Kostenfaktor dar, der oft übersehen wird. Wenn Sie eine Lambda-Funktion erstellen, weisen Sie eine bestimmte Menge an Speicher zu (z.B. 128MB, 256MB, 512MB). Sie bezahlen für diesen zugewiesenen Speicher, unabhängig davon, wie viel Ihre Funktion tatsächlich nutzt. Zusätzlich steigt die CPU-Leistung proportional zur Speichermenge. Wenn Sie also 1 GB Speicher für ein einfaches Python-Skript zuweisen, das nur 128 MB benötigt, bezahlen Sie nicht nur zu viel für den Speicher; Sie bezahlen auch zu viel für die CPU-Zyklen, die es nicht braucht.
Ich habe das an meinen eigenen Erfahrungen mit einer Lambda-Funktion zur Datenverarbeitung gelernt, die ursprünglich mit 1 GB Speicher „nur für den Fall“ konfiguriert war. Als ich mir ihre CloudWatch-Metriken zur Speichernutzung ansah, blieb sie konstant unter 200 MB, selbst während Spitzenlastzeiten. Wir zahlten also im Wesentlichen für 800 MB ungenutzten RAM und die entsprechenden CPU-Boosts.
Praxiste Beispiel 2: Speichereinteilung mit Lambda Power Tuning Optimieren
Manuell den optimalen Speichereinstellungen zu bestimmen, kann mühsam sein. Sie müssen bereitstellen, testen, überwachen, anpassen und wiederholen. Zum Glück gibt es ein hervorragendes Open-Source-Tool namens AWS Lambda Power Tuning (entwickelt von Alex Casalboni bei AWS), das diesen Prozess erleichtert.
Es ist eine serverlose Anwendung, die Ihnen hilft, den optimalen Speichereinstellungen für Ihre Lambda-Funktionen basierend auf Kosten und Leistung zu visualisieren und zu identifizieren. Sie stellen es in Ihrem AWS-Konto bereit und können es dann verwenden, um Ihre Funktionen zu testen.
So funktioniert es in der Regel:
- Sie stellen das Power Tuning-Tool über das Serverless Application Repository oder SAM bereit.
- Sie rufen eine Zustandsmaschine (erstellt von dem Tool) mit der ARN Ihrer Lambda-Funktion und einem Payload auf.
- Die Zustandsmaschine ruft Ihre Lambda mehrmals mit unterschiedlichen Speicher-Konfigurationen (z.B. 128 MB, 256 MB, 512 MB, 1024 MB usw.) auf.
- Sie analysiert dann die Ausführungsprotokolle und bietet eine Visualisierung, die die Kompromisse zwischen Kosten und Geschwindigkeit für jede Speichereinstellung zeigt.
Für meine Lambda-Datenverarbeitungsfunktion hat der Test mit dem Power Tuner gezeigt, dass 256 MB der richtige Mittelwert für die Kosten waren, mit einer vernachlässigbaren Leistungsverschlechterung im Vergleich zu 1 GB. Wir haben sofort die Speicherkapazität auf 256 MB reduziert, was zu einer Reduzierung der Rechenkosten um 75 % für diese spezifische Funktion führte. Es war kein einmaliger Schlag; ich habe mittlerweile dafür gesorgt, dass es eine Standardpraxis ist, neue Funktionen oder solche, die mit diesem Tool neu bewertet werden, so zu behandeln.
Um es zu verwenden, würden Sie typischerweise die Zustandsmaschine nach dem Deployment mit etwas wie diesem (unter Anpassung der ARN und der Payload) starten:
aws stepfunctions start-execution \
--state-machine-arn "arn:aws:states:REGION:ACCOUNT_ID:stateMachine:powerTuningStateMachine" \
--input '{ "lambdaARN": "arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_FUNCTION_NAME", "num": 100, "payload": {}, "parallel": 5 }'
Die Ausgabe liefert ein klares Diagramm, das genau zeigt, wo Ihre Kosten und Ihre Geschwindigkeit sich schneiden für eine optimale Leistung. Das ist ein wesentlicher Schritt zur Kostenoptimierung.
Die Verbosität der Protokolle und Kaltstarts
Zwei weitere Bereiche, die Sie oft überraschen, sind die Verbosität der Protokolle und Kaltstarts. CloudWatch-Protokolle sind nicht kostenlos. Jede Zeile, die von Ihrer Lambda-Funktion ausgegeben wird, wird erfasst und gespeichert, und dafür zahlen Sie. Während ein gutes Protokoll entscheidend für das Debugging ist, kann eine zu verbositätsreiche Protokollierung (z. B. das Drucken ganzer Objekte oder das unnötige Wiederholen von Statusmeldungen) schnell Ihre CloudWatch-Protokollrechnung aufblähen.
Ich habe einige Funktionen gefunden, die den vollständigen Körper der HTTP-Anfrage bei jedem Aufruf protokollierten. Obwohl dies für die anfängliche Entwicklung nützlich war, war es in der Produktion nur Lärm und Kosten. Eine schnelle Anpassung, um nur die notwendigen Metadaten (Anforderungs-ID, Statuscode, Endpunkt) zu protokollieren, hat unseren Protokollaufwand erheblich reduziert.
Kaltstarts, obwohl sie nicht direkt einen „Kosten“-Faktor darstellen, beeinflussen die Benutzererfahrung und können indirekt zu mehr Wiederholungen oder längeren Abrechnungszeiträumen führen, wenn Ihre Funktion auf Ressourcen warten muss. Obwohl AWS bedeutende Fortschritte gemacht hat, um Kaltstartzeiten zu reduzieren, kann die Optimierung der Bundle-Größe Ihrer Funktion und das Vermeiden komplexer Initialisierungslogik außerhalb des Handlers weiterhin einen Unterschied machen. Für latenzempfindliche kritische Funktionen ist die bereitgestellte Konkurrenz eine Option, aber beachten Sie, dass Sie für diese zugewiesene Konkurrenz auch dann zahlen, wenn sie ungenutzt ist.
Praktisches Beispiel 3: Intelligente Protokollierung und Umgebungsvariablen
Für die Protokollierung ist die einfachste Lösung oft die beste. Verwenden Sie Umgebungsvariablen, um die Protokollierungsstufen zu steuern. In Python können Sie beispielsweise Folgendes tun:
import os
import logging
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO').upper()
logging.basicConfig(level=LOG_LEVEL)
logger = logging.getLogger()
def lambda_handler(event, context):
logger.debug("Dies ist eine Debug-Nachricht, sichtbar nur wenn LOG_LEVEL auf DEBUG gesetzt ist")
logger.info("Verarbeitung des Ereignisses: %s", event.get('request_id'))
try:
# ... Logik der Funktion ...
logger.debug("Fertig mit der Verarbeitung für request_id: %s", event.get('request_id'))
return {
'statusCode': 200,
'body': 'Erfolg'
}
except Exception as e:
logger.error("Fehler bei der Verarbeitung von request_id %s: %s", event.get('request_id'), str(e), exc_info=True)
return {
'statusCode': 500,
'body': 'Fehler'
}
Indem Sie LOG_LEVEL in der Produktion auf INFO und in der Entwicklung/Staging auf DEBUG setzen, können Sie Ihre CloudWatch-Logs-Rechnung erheblich reduzieren, ohne die Beobachtbarkeit zu opfern, wenn Sie sie benötigen.
Ein weiterer Tipp ist, darauf zu achten, was außerhalb des Handlers initialisiert wird. Jeder Code, der direkt im globalen Scope Ihrer Lambda-Funktion steht, wird während des Kaltstarts ausgeführt. Wenn Sie rechenintensive Vorgänge wie das Pooling von Datenbankverbindungen oder das Importieren großer Bibliotheken haben, ziehen Sie in Betracht, diese hinauszuzögern, bis sie tatsächlich im Handler benötigt werden, oder stellen Sie sicher, dass sie effizient für die nächsten Warmaufrufe zwischengespeichert werden.
Konkrete Maßnahmen für Ihren Serverless-Kostenkampf
Wir haben also schon eine Menge abgedeckt. Hier ist eine Zusammenfassung der praktischen Schritte, die Sie sofort unternehmen können, um diese heimtückischen Lambda-Kosten zu senken:
- Überwachen Sie unermüdlich: Zufrieden Sie sich nicht damit, nur einen Blick auf Ihre gesamte AWS-Rechnung zu werfen. Erkunden Sie die CloudWatch-Metriken für Aufrufe, Dauer und Speicherauslastung für jede Lambda-Funktion. Richten Sie Alarme für unerwartete Spitzen ein.
- Konsolidieren Sie die Cron-Aufgaben: Wenn Sie viele kleine, geplante Lambda-Funktionen haben, ziehen Sie in Betracht, diese in einem einzigen „Wartungs“job zu bündeln, der die Aufgaben nach einem weniger häufigen Zeitplan verteilt. Dies verringert erheblich die Anzahl der Aufrufe.
- Optimieren Sie die Speicherkapazität: Verwenden Sie Tools wie AWS Lambda Power Tuning, um die optimale Speichereinstellung für Ihre Funktionen zu finden. Verlassen Sie sich nicht lediglich auf Vermutungen und Überprovisionierung. Vergessen Sie nicht, dass mehr Speicher mehr CPU bedeutet, und Sie zahlen für beides.
- Kontrollieren Sie die Verbosität der Protokolle: Implementieren Sie Protokollierungsebenen, die durch Umgebungsvariablen gesteuert werden (z. B.
INFOfür die Produktion,DEBUGfür die Entwicklung). Vermeiden Sie es, die vollständigen Anfragetexte oder übermäßige interne Statusmeldungen in der Produktion zu protokollieren. Ihre CloudWatch-Protokollrechnung wird es Ihnen danken. - Überprüfen Sie ungenutzte Funktionen: Auditieren Sie regelmäßig Ihre Lambda-Funktionen. Gibt es alte, experimentelle oder nicht mehr benötigte Funktionen, die noch aktiv sind und Kosten verursachen? Löschen Sie sie!
- Überwachen Sie die Paketgröße: Kleinere Bereitstellungspakete bedeuten schnellere Kaltstarts und geringere Speicherkosten. Schließen Sie nur die notwendigsten Abhängigkeiten ein.
- Verstehen Sie Ihr Preismodell: Lesen Sie die Lambda-Preisseite nochmals durch. Verstehen Sie, wie Aufrufe, GB-Sekunden und Datenübertragungen abgerechnet werden. Wissen ist Macht, besonders wenn es um Ihr Geld geht.
Den Serverless-Monster zu dominieren, bedeutet nicht, Serverless zu vermeiden; es geht darum, klug und absichtlich damit umzugehen. Flexibilität und Skalierbarkeit sind unbezahlbar, aber ohne angemessene Wachsamkeit können sich diese „kleinen“ Kosten summieren und einen erheblichen Teil Ihres Budgets ausmachen. Packen Sie es an, überwachen Sie, optimieren Sie und sparen Sie!
Das war’s für mich heute. Lassen Sie es mich in den Kommentaren wissen, wenn Sie weitere Tipps oder Tricks zur Kostenoptimierung für Lambda haben!
🕒 Published: