Hallo zusammen, hier ist Jules Martin, zurück auf agntmax.com!
Heute möchte ich etwas ansprechen, das mich seit etwa einem Jahr beschäftigt und wahrscheinlich auch viele von euch: die steigenden Kosten für Cloud-Infrastruktur, insbesondere im Hinblick auf serverlose Funktionen. Wir alle wurden von dem Traum des „Zahlens für das, was Sie nutzen“ verführt, und lange Zeit schien das eine Realität zu sein. Aber in letzter Zeit habe ich gesehen, wie die Rechnungen gestiegen sind, manchmal auf unerklärliche Weise, selbst wenn die Verkehrsmuster stabil schienen. Es ist, als würden wir von der gleichen Flexibilität, die wir angenommen hatten, aufgefressen. Lassen Sie uns also etwas sehr Spezifisches 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 Benutzeranmeldung und das Sitzungsmanagement verwaltet. Er ist fast vollständig auf AWS Lambda, API Gateway, DynamoDB und Cognito aufgebaut. Lange Zeit waren die Kosten vollkommen vorhersehbar. Dann, letzten Sommer, sprang unsere AWS-Rechnung für diesen speziellen Dienst um etwa 15 %. Keine neuen Funktionen, keine signifikanten Verkehrsspitzen. Zunächst schrieb ich das einer saisonalen Schwankung oder einem kleinen Bug zu, den ich noch nicht gefunden hatte. Aber als die Rechnung des folgenden Monats noch höher ausfiel, wusste ich, dass ich tiefer graben musste. Es war nicht nur ein Anstieg; es war ein Trend, und es kostete uns echtes Geld.
Die Illusion der „Kostenlosen“ Stufen und die Realität der „Mini“-Aufrufe
Einer der größten Vorteile von serverlos, insbesondere für Startups oder kleine Teams, ist die großzügige kostenlose Stufe. Und sie ist großzügig! Eine Million kostenlose Aufrufe pro Monat für Lambda, zusätzlich zu einer erheblichen Menge an Rechenzeit. Das Problem ist, dass, während Ihre Anwendung wächst, diese „kostenlosen“ Aufrufe schneller verschwinden als ein Stück Pizza bei einem Tech-Meetup. Oft übersehen wird das gesamte Volumen an „Mini“-Aufrufen, die anscheinend unbedeutend sind und sich summieren. Denken Sie an Cron-Jobs, interne Gesundheitsprüfungen oder sogar Wiederholungsmechanismen von anderen Diensten. Jeder dieser Aufrufe zählt.
Meine Untersuchung unseres Authentifizierungsdienstes hat genau das ergeben. Wir hatten eine Lambda-Funktion, nennen wir sie auth-token-refresher, die dazu gedacht war, interne Servicetoken regelmäßig zu aktualisieren. Sie war so programmiert, dass sie alle fünf Minuten ausgeführt wurde. 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 plötzlich sind das über 25.000 Aufrufe nur für eine kleine Wartungsaufgabe. Wir hatten ein Dutzend solcher Funktionen. Auf einmal waren unsere „Mini“-Aufrufe nicht mehr so klein.
Die Schuldigen Finden: CloudWatch-Metriken Sind Ihr Bester Freund
Der erste Schritt, um dieses Biest zu bezwingen, besteht darin, zu wissen, wohin Ihr Geld fließt. AWS CloudWatch ist hier unerlässlich. Schauen Sie sich nicht nur das allgemeine Abrechnungs-Dashboard an; erkunden Sie die spezifischen Metriken Ihrer Lambda-Funktionen.
Hier ist, worauf ich mich konzentriert habe:
- Aufrufe: Das ist die einfachste Metrik. Hohe Aufrufzahlen für Funktionen, die keinen direkten Benutzerverkehr verarbeiten, sind sofortige Warnsignale.
- Dauer: Wie lange dauert jeder Aufruf? Längere Dauern bedeuten höhere Rechenkosten.
- Speicherverbrauch: Überprovisionieren Sie Speicher für Ihre Funktionen? Sie zahlen für das, was Sie zuweisen, nicht für das, was Sie tatsächlich nutzen.
- Fehlerrate: Hohe Fehlerraten können zu Wiederholungen führen, was mehr Aufrufe und verschwendete Rechenzyklen bedeutet.
Für unseren auth-token-refresher habe ich die Metrik `Aufrufe` untersucht. Tatsächlich lief sie wie eine Uhr, alle fünf Minuten. Die Dauer war minimal, nur etwa 50 ms. Aber das enorme Volumen trug zu unseren Gesamtkosten für Aufrufe bei.
Praktisches Beispiel 1: Konsolidieren und Intelligenter Planen
Die Lösung für auth-token-refresher und mehrere andere ähnliche Wartungsfunktionen war überraschend einfach: die Konsolidierung. Anstatt einzelne Lambda-Funktionen zu haben, die durch CloudWatch-Ereignisse (oder EventBridge heutzutage) zu unterschiedlichen Zeiten ausgelöst werden, habe ich eine einzige Lambda-Funktion „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 (wurde alle 5 Minuten ausgeführt)
if current_minute % 10 == 0: # Wird jetzt alle 10 Minuten ausgeführt
print("Ausführung der Aktualisierung des Authentifizierungstokens...")
# Rufen Sie die tatsächliche Logik zur Aktualisierung des Tokens oder eine andere interne Funktion auf
refresh_auth_token()
# Aufgabe 2: Alte Protokolle bereinigen (wurde stündlich ausgeführt)
if current_hour % 1 == 0 and current_minute == 0: # Wird zu Beginn der Stunde ausgeführt
print("Ausführung der Protokollbereinigung...")
cleanup_old_logs()
# Aufgabe 3: Status externer Dienste überprüfen (wurde alle 30 Minuten ausgeführt)
if current_minute == 0 or current_minute == 30:
print("Überprüfung des Status externer Dienste...")
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 Protokolle ...
pass
def check_external_service():
# ... tatsächliche Logik zur Überprüfung externer Dienste ...
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 in Bezug auf die Protokollaufnahme in CloudWatch und die API Gateway-Aufrufe (falls einer von ihnen über API Gateway exponiert war).
Die Falle der Überprovisionierung von Speicher
Dies ist ein weiterer subtiler Kostenfaktor, der oft übersehen wird. Wenn Sie eine Lambda-Funktion erstellen, weisen Sie eine bestimmte Menge an Speicher zu (z. B. 128 MB, 256 MB, 512 MB). Sie zahlen für diesen zugewiesenen Speicher, egal wie viel Ihre Funktion tatsächlich nutzt. Darüber hinaus steigt die CPU-Leistung proportional zur Speicherzuweisung. Wenn Sie also 1 GB Speicher für ein einfaches Python-Skript zuweisen, das nur 128 MB benötigt, zahlen Sie nicht nur zu viel für den Speicher; Sie zahlen auch für zusätzliche CPU-Zyklen, die Sie nicht benötigen.
Ich habe dies am eigenen Leib erfahren mit einer Lambda-Funktion zur Datenverarbeitung, die ursprünglich mit 1 GB Speicher „für alle Fälle“ konfiguriert war. Als ich mir ihre CloudWatch-Metriken für die Speichernutzung ansah, blieb sie selbst in Zeiten hoher Last systematisch unter 200 MB. Wir zahlten im Grunde für 800 MB ungenutzten RAM und den entsprechenden CPU-Boost.
Praktisches Beispiel 2: Speicherzuweisung mit Lambda Power Tuning Optimieren
Die manuelle Bestimmung der optimalen Speicheranpassung kann mühsam sein. Sie müssen bereitstellen, testen, überwachen, anpassen und wiederholen. Glücklicherweise gibt es ein hervorragendes Open-Source-Tool namens AWS Lambda Power Tuning (entwickelt von Alex Casalboni bei AWS), das diesen Prozess erleichtert.
Es handelt sich um eine serverlose Anwendung, die Ihnen hilft, die optimale Speicheranpassung 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 im Allgemeinen:
- Sie stellen das Power Tuning-Tool über das Serverless Application Repository oder SAM bereit.
- Sie rufen eine Zustandsmaschine (die vom Tool erstellt wurde) mit der ARN Ihrer Lambda-Funktion und einem Payload auf.
- Die Zustandsmaschine ruft Ihre Lambda-Funktion mehrere Male mit unterschiedlichen Speicherzuweisungen auf (z. B. 128 MB, 256 MB, 512 MB, 1024 MB usw.).
- Sie analysiert dann die Ausführungsprotokolle und liefert eine Visualisierung, die die Kosten- und Geschwindigkeitskompromisse für jede Speicheranpassung zeigt.
Für meine Lambda-Funktion zur Datenverarbeitung habe ich beim Durchlaufen des Power Tuners festgestellt, dass 256 MB die beste Wahl in Bezug auf die Kosten waren, mit einer vernachlässigbaren Leistungseinbuße im Vergleich zu 1 GB. Wir haben sofort die Speicherkapazität auf 256 MB reduziert, was zu einer Reduzierung der Berechnungskosten um 75 % für diese spezifische Funktion führte. Dies war kein Einzelfall; ich habe mir seitdem angewöhnt, neue oder neu bewertete Funktionen durch dieses Tool zu führen.
Um es zu verwenden, würden Sie nach dem Deployment normalerweise die Zustandsmaschine mit etwas wie diesem starten (ARN und Payload anpassen):
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 für eine optimale Leistung kreuzen. Das ist eine bedeutende Veränderung für die Kostenoptimierung.
Protokollierungs-Verbosity und Kaltstarts
Zwei weitere Bereiche, die Sie oft überraschen können, sind die Verbosität der Protokolle und die Kaltstarts. Die CloudWatch-Protokolle sind nicht kostenlos. Jede Zeile, die Ihre Lambda-Funktion ausgibt, wird erfasst und gespeichert, und dafür zahlen Sie. Obwohl eine gute Protokollierung entscheidend für das Debugging ist, kann eine zu ausführliche Protokollierung (z. B. das Ausgeben ganzer Objekte oder das unnötige Wiederholen von Statusmeldungen) schnell Ihre CloudWatch Logs-Rechnung in die Höhe treiben.
Ich habe einige Funktionen gefunden, die den gesamten Körper der HTTP-Anfragen bei jeder Invocation protokolliert haben. Obwohl dies für die anfängliche Entwicklung hilfreich war, erzeugte es in der Produktion nur Rauschen und kostete Geld. Eine schnelle Anpassung, um nur die wesentlichen Metadaten (Anfrage-ID, Statuscode, Endpunkt) zu protokollieren, hat unsere Protokollaufnahme erheblich reduziert.
Kaltstarts, obwohl sie nicht direkt einen „Kosten“-Faktor darstellen, beeinflussen die Benutzererfahrung und können indirekt zu mehr Wiederholungen oder längeren Abrechnungszeiten führen, wenn Ihre Funktion auf Ressourcen warten muss. Obwohl AWS erhebliche Fortschritte gemacht hat, um die Kaltstartzeiten zu reduzieren, kann die Optimierung der Bundle-Größe Ihrer Funktion und das Vermeiden komplexer Initialisierungslogik außerhalb des Handlers immer noch einen Unterschied machen. Für latenzempfindliche kritische Funktionen ist die bereitgestellte Konkurrenz eine Option, aber beachten Sie, dass Sie für diese zugewiesene Konkurrenz bezahlen, selbst wenn sie ungenutzt ist.
Praktisches Beispiel 3: Intelligente Protokolle und Umgebungsvariablen
Für das Protokoll 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 DEBUG ist")
logger.info("Verarbeitung des Ereignisses: %s", event.get('request_id'))
try:
# ... Funktionslogik ...
logger.debug("Verarbeitung abgeschlossen 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'
}
Durch das Setzen von LOG_LEVEL auf INFO in der Produktion und DEBUG in der Entwicklung/Staging 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 Geltungsbereich Ihrer Lambda-Funktion steht, wird beim Kaltstart ausgeführt. Wenn Sie kostspielige Operationen wie das Pooling von Datenbankverbindungen oder große Bibliotheksimporte haben, ziehen Sie in Betracht, diese bis zu dem Zeitpunkt zu verschieben, an dem sie tatsächlich im Handler benötigt werden, oder stellen Sie sicher, dass sie effizient für die nachfolgenden heißen Aufrufe zwischengespeichert werden.
Wichtige Punkte für Ihre Kostenoptimierung im Serverless-Bereich
Okay, wir haben eine Menge abgedeckt. Hier ist eine Zusammenfassung der praktischen Schritte, die Sie jetzt unternehmen können, um diese heimtückischen Lambda-Kosten zu senken:
- Überwachen Sie unermüdlich: Beschränken Sie sich nicht darauf, nur einen Blick auf Ihre gesamte AWS-Rechnung zu werfen. Erkunden Sie die CloudWatch-Metriken für Aufrufe, Dauer und Speichernutzung für jede Lambda-Funktion. Richten Sie Alarme für unerwartete Spitzen ein.
- Konsolidieren Sie Cron-Jobs: Wenn Sie mehrere kleine Lambda-Funktionen geplant haben, ziehen Sie in Betracht, diese zu einer einzigen „Maintenance Runner“-Funktion zusammenzufassen, die Aufgaben nach einem weniger häufigen Zeitplan verteilt. Dies reduziert die Anzahl der Aufrufe erheblich.
- Optimieren Sie die Speicherkapazität: Verwenden Sie Tools wie AWS Lambda Power Tuning, um die optimale Speicherkonfiguration für Ihre Funktionen zu finden. Treffen Sie keine Annahmen und provisionieren Sie nicht übermäßig. Denken Sie daran, mehr Speicher bedeutet mehr CPU, und Sie zahlen für beides.
- Kontrollieren Sie die Verbosität der Protokolle: Implementieren Sie Protokollierungsstufen, die von Umgebungsvariablen gesteuert werden (z. B.
INFOfür die Produktion,DEBUGfür die Entwicklung). Vermeiden Sie es, die gesamten Anfragekörper oder übermäßige interne Zustände in der Produktion zu protokollieren. Ihre CloudWatch Logs-Rechnung wird es Ihnen danken. - Überprüfen Sie ungenutzte Funktionen: Überprüfen Sie regelmäßig Ihre Lambda-Funktionen. Gibt es alte, experimentelle oder veraltete 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 notwendigen Abhängigkeiten ein.
- Verstehen Sie Ihr Preismodell: Lesen Sie die Lambda-Preisseite erneut. Verstehen Sie, wie Aufrufe, GB-Sekunden und Datenübertragungen abgerechnet werden. Wissen ist Macht, besonders wenn es um Ihr Portemonnaie geht.
Den Serverless-Monster zu zähmen, geht nicht darum, Serverless zu vermeiden; es geht darum, schlau und absichtlich damit umzugehen, wie wir es nutzen. Flexibilität und Skalierbarkeit sind unbezahlbar, aber ohne angemessene Wachsamkeit können diese „kleinen“ Kosten sich summieren und einen erheblichen Teil Ihres Budgets ausmachen. Gehen Sie voran, überwachen Sie, optimieren Sie und sparen Sie!
Das war’s für heute von mir. Lassen Sie mich in den Kommentaren wissen, ob Sie weitere Tipps oder Ratschläge zur Kostenoptimierung von Lambda haben!
🕒 Published: