Fehler bei erhöhter Latenz in Ihrer Anwendung beheben

In vielen Fällen führt eine erhöhte Latenz in Ihrer Anwendung letztendlich zu 5xx-Serverfehlern. Daher ist es sinnvoll, einem ähnlichen Satz von Schritten zur Fehlerbehebung zu folgen, um die Ursache der Fehler- und Latenzspitzen einzugrenzen, da die Ursachen bei beiden möglicherweise identisch sind.

Problem beheben

Definieren Sie zuerst den Umfang des Problems so genau wie möglich, indem Sie relevante Informationen erfassen. Im Folgenden finden Sie einige Vorschläge für Informationen, die möglicherweise relevant sind.

  • Welche Anwendungs-IDs, Dienste und Versionen sind betroffen?
  • Welche spezifischen Endpunkte in der Anwendung sind betroffen?
  • Wirkt sich dies auf alle Clients weltweit oder auf eine bestimmte Teilmenge von Clients aus?
  • Wie lauten Start und Ende des Vorfalls? Sie sollten die Zeitzone angeben.
  • Welche spezifischen Fehler werden angezeigt?
  • Was ist das beobachtete Latenzdelta, das normalerweise als Erhöhung bei einem bestimmten Perzentil angegeben wird? Beispiel: die Latenz war beim 90. Perzentil um 2 Sekunden erhöht.
  • Wie haben Sie die Latenz gemessen? Wurde die Anfrage insbesondere auf dem Client gemessen oder ist sie in Cloud Logging und/oder in den Cloud Monitoring-Latenzdaten sichtbar, die von der App Engine-Bereitstellungsinfrastruktur bereitgestellt werden?
  • Welche Abhängigkeiten hat Ihre Anwendung und hat es Vorfälle mit diesen gegeben?
  • Haben Sie kürzlich Code-, Konfigurations- oder Arbeitslaständerungen vorgenommen, die dieses Problem ausgelöst haben könnten?

Eine Anwendung kann über ein eigenes benutzerdefiniertes Monitoring und Logging verfügen, mit dem Sie den Problembereich über die obigen Vorschläge hinaus eingrenzen können. Wenn Sie den Umfang des Problems eingrenzen, werden Sie zur wahrscheinlichen Ursache geführt und können die nächsten Schritte zur Fehlerbehebung ermitteln.

Bestimmen, was fehlgeschlagen ist

Bestimmen Sie als Nächstes, welche Komponente im Anfragepfad hauptsächlich die Latenz oder Fehler verursacht. Die Hauptkomponenten im Anfragepfad sind:

Client -> Internet -> Google Front End (GFE) -> App Engine-Bereitstellungsinfrastruktur -> Anwendungsinstanz

Wenn die in Schritt 1 erfassten Informationen nicht auf die Fehlerquelle verweisen, sollten Sie zuerst den Zustand und die Leistung Ihrer Anwendungsinstanzen prüfen.

Um herauszufinden, ob das Problem bei Ihrer Anwendungsinstanz liegt, können Sie sich die App Engine-Anfragelogs ansehen: Wenn Sie HTTP-Statuscodefehler oder eine erhöhte Latenz in diesen Logs sehen, bedeutet dies in der Regel, dass das Problem bei der Instanz liegt, auf der Ihre Anwendung ausgeführt wird.

Es gibt einen Fall, in dem Häufungen von Fehlern und hohe Latenz in den Anfragelogs möglicherweise nicht durch die Anwendungsinstanz selbst verursacht werden: Wenn die Anzahl der Instanzen Ihrer Anwendung nicht hochskaliert wurde, um dem Trafficaufkommen gerecht zu werden, können die Instanzen überlastet sein, was zu häufigeren Fehlern und hoher Latenz führt.

Wenn in Cloud Monitoring häufige Fehler oder hohe Latenz auftreten, können Sie im Allgemeinen davon ausgehen, dass das Problem vor dem Load-Balancer liegt, der die App Engine-Messwerte aufzeichnet. In den meisten Fällen weist dies auf ein Problem in den Anwendungsinstanzen hin.

Wenn Sie jedoch höhere Latenz oder häufige Fehler in den Monitoring-Messwerten sehen, aber nicht in den Anfragelogs, sind weitere Nachforschungen erforderlich. Dies kann auf einen Fehler auf der Load-Balancing-Ebene hinweisen oder darauf hindeuten, dass die Instanzen so einen schwerwiegenden Fehler haben, dass der Load-Balancer keine Anfragen an diese weiterleiten kann. Um zwischen diesen Fällen zu unterscheiden, können Sie sich die Anfragelogs direkt vor dem Beginn des Vorfalls ansehen. Wenn die Anfragelogs unmittelbar vor dem Fehler eine zunehmende Latenz zeigen, bedeutet dies, dass die Anwendungsinstanzen selbst versagen, bevor der Load-Balancer keine Anfragen mehr an sie weiterleitet.

Szenarien, die Vorfälle verursachen können

Im Folgenden sind einige Szenarien aufgeführt, die Nutzer gesammelt haben.

Client

Client-IP einer geografischen Region zuordnen

Google löst den Hostnamen für die App-Engine-Anwendung zum nächstgelegenen GFE zum Client auf, basierend auf der Client-IP-Adresse, die bei der DNS-Suche verwendet wird. Wenn der DNS-Resolver des Clients nicht das EDNS0-Protokoll verwendet, werden Clientanfragen möglicherweise nicht an das nächstgelegene GFE weitergeleitet.

Internet

Schlechte Internetverbindung

Führen Sie den folgenden Befehl auf Ihrem Client aus, um festzustellen, ob das Problem eine schlechte Internetverbindung ist.

$ curl -s -o /dev/null -w '%{time_connect}\n' <hostname>

Der Wert für time_connect stellt im Allgemeinen die Latenz der Clientverbindung zum nächsten Google Front End dar. Wenn diese Verbindung langsam ist, können Sie mithilfe von traceroute weitere Fehler beheben, um festzustellen, welcher Hop im Netzwerk die Verzögerung verursacht.

Sie können Tests von Clients an verschiedenen geografischen Standorten ausführen. Anfragen werden automatisch an das nächstgelegene Google-Rechenzentrum weitergeleitet, was je nach Standort des Clients variiert.

Clients mit niedriger Bandbreite

Die Anwendung reagiert möglicherweise schnell, aber die Antwort kann durch Netzwerkengpässe verlangsamt werden, die dazu führen, dass die App Engine-Bereitstellungsinfrastruktur Pakete nicht so schnell wie möglich über das Netzwerk sendet.

Google Front End (GFE)

HTTP/2-Head-of-Line-Blocking

HTTP/2-Clients, die mehrere Anfragen parallel senden, können aufgrund des Head-of-Line-Blockings im GFE eine erhöhte Latenz aufweisen. Die beste Lösung ist, für Clients ein Upgrade auf das QUIC-Protokoll durchzuführen.

SSL-Terminierung für benutzerdefinierte Domains

Das GFE beendet die SSL-Verbindung. Wenn Sie eine benutzerdefinierte Domain anstelle einer appspot.com-Domain verwenden, ist ein zusätzlicher Hop für die SSL-Terminierung erforderlich. Dies kann zu Latenzen bei Anwendungen führen, die in einigen Regionen ausgeführt werden.

App Engine-Bereitstellungsinfrastruktur

Dienstweiter Vorfall

Google veröffentlicht Details zu schwerwiegenden dienstweiten Fehlern unter https://status.cloud.google.com/. Beachten Sie, dass Google schrittweise Rollouts durchführt, sodass ein dienstweiter Vorfall wahrscheinlich nicht alle Instanzen gleichzeitig betrifft.

Autoscaling

Traffic zu schnell hochskaliert

Beim App Engine-Autoscaling werden Ihre Instanzen möglicherweise nicht so schnell skaliert, wie der Traffic zunimmt, was zu einer vorübergehenden Überlastung führt. In der Regel geschieht dies, wenn der Traffic nicht nativ von Endnutzern generiert wird und stattdessen von einem Computerprogramm generiert wird. Die beste Lösung ist, das System, das den Traffic generiert, zu drosseln.

Trafficspitzen

Trafficspitzen können zu einer höheren Latenz führen, wenn eine automatisch skalierte Anwendung schneller hochskaliert werden muss, als es ohne Beeinträchtigung der Latenz möglich ist. Endnutzer-Traffic verursacht in der Regel keine häufigen Trafficspitzen. Wenn Sie dies sehen, sollten Sie untersuchen, was die Trafficspitzen verursacht. Wenn ein Batchsystem in Intervallen ausgeführt wird, können Sie den Traffic möglicherweise ausgleichen oder andere Skalierungseinstellungen verwenden.

Autoscaling-Einstellungen

Das Autoscaling kann anhand der Skalierungsmerkmale Ihrer Anwendung konfiguriert werden. Diese Skalierungsparameter können sich in bestimmten Szenarien ungünstig entwickeln.

Anwendungen der flexiblen App Engine-Umgebung werden basierend auf der CPU-Auslastung skaliert. Allerdings kann die Anwendung während eines Vorfalls E/A-gebunden werden, was zur Überlastung von Instanzen mit einer hohen Anzahl von Anfragen führt, da keine CPU-basierte Skalierung erfolgt.

Die Skalierungseinstellungen der App Engine-Standardumgebung können zu Latenzen führen, wenn sie zu aggressiv festgelegt sind. Wenn Sie Serverantworten mit dem Statuscode 500 und der Nachricht Request was aborted after waiting too long to attempt to service your request in Ihren Logs sehen, wurde das Zeitlimit überschritten, während die Anfrage in der Warteschlange auf eine freie Instanz wartete.

Verwenden Sie keine manuelle Skalierung der App Engine-Standardumgebung, wenn Ihre Anwendung Endnutzertraffic verarbeitet. Manuelle Skalierung ist besser für Arbeitslasten wie Aufgabenwarteschlangen. Bei manueller Skalierung kann es zu längeren Wartezeiten kommen, auch wenn Sie genügend Instanzen bereitgestellt haben.

Verwenden Sie die einfache Skalierung der App Engine-Standardumgebung nicht für latenzempfindliche Anwendungen. Dieser Skalierungstyp ist darauf ausgelegt, die Kosten zu Lasten der Latenz zu minimieren.

Die Standardskalierungseinstellungen der App Engine-Standardumgebung bieten eine optimale Latenz für die meisten Anwendungen. Wenn Sie weiterhin Anfragen mit hoher Wartezeit sehen, können Sie eine Mindestanzahl von Instanzen angeben. Wenn Sie die Skalierungseinstellungen zur Minimierung der Kosten optimieren, indem Sie inaktive Instanzen minimieren, besteht die Gefahr, dass Latenzspitzen auftreten, wenn die Last plötzlich ansteigt.

Wir empfehlen Ihnen, die Leistung mit den Standardskalierungseinstellungen zu vergleichen und nach jeder Änderung an diesen Einstellungen eine neue Benchmark auszuführen.

Deployments

Eine erhöhte Latenz kurz nach einer Bereitstellung gibt an, dass Sie vor der Migration des Traffics nicht ausreichend vertikal skaliert haben. Neuere Instanzen haben möglicherweise keine lokalen Caches vorbereitet und können daher langsamer ausgeführt werden als ältere Instanzen.

Stellen Sie keine App Engine-Anwendung bereit, die denselben Versionsnamen wie eine vorhandene Anwendungsversion verwendet, um Latenzspitzen zu vermeiden. Wenn Sie einen vorhandenen Versionsnamen wiederverwenden, können Sie den Traffic nicht langsam zur neuen Version migrieren. Anfragen können langsamer sein, da jede Instanz innerhalb kurzer Zeit neu gestartet wird. Sie müssen die Bereitstellung auch noch einmal ausführen, wenn Sie zur vorherigen Version zurückkehren möchten.

Anwendungsinstanz

Anwendungscode

Probleme in Anwendungscode können sehr schwierig zu debuggen sein, insbesondere wenn sie zeitweise auftreten oder nicht leicht reproduziert werden können. Zur Diagnose von Problemen empfehlen wir, Ihre Anwendung mit Logging, Monitoring und Tracing zu instrumentieren. Sie können versuchen, Probleme mit Cloud Profiler zu diagnostizieren. In diesem Beispiel wird gezeigt, wie Sie die Latenz von Ladeanfragen mit Cloud Trace diagnostizieren, um zusätzliche Zeitinformationen für jede Anfrage hochzuladen.

Sie können auch versuchen, das Problem in einer lokalen Entwicklungsumgebung zu reproduzieren. Dadurch können Sie sprachspezifische Debugging-Tools ausführen, die möglicherweise nicht in App Engine ausgeführt werden können.

Wenn Sie die Anwendung in der flexiblen App Engine-Umgebung ausführen, können Sie eine SSH-Verbindung zu einer Instanz herstellen und einen Thread-Dump erstellen, um den aktuellen Status Ihrer Anwendung abzurufen. Sie können versuchen, das Problem in einem Lasttest zu reproduzieren oder die Anwendung lokal auszuführen. Sie können die Instanzgröße erhöhen, um zu sehen, ob das Problem dadurch behoben wird. Beispielsweise kann ein erweiterter RAM die Probleme von Anwendungen beheben, bei denen es aufgrund der automatischen Speicherbereinigung zu Verzögerungen kommt.

Damit Sie besser verstehen, warum Ihre Anwendung fehlschlägt und welche Engpässe auftreten, können Sie einen Lasttest Ihrer Anwendung ausführen, bis ein Fehler auftritt. Legen Sie eine maximale Anzahl von Instanzen fest und erhöhen Sie dann die Last nach und nach, bis die Anwendung fehlschlägt.

Wenn das Latenzproblem mit der Bereitstellung einer neuen Version Ihres Anwendungscodes korreliert, können Sie ein Rollback durchführen, um festzustellen, ob die neue Version den Vorfall verursacht hat. Bei einer kontinuierlichen Bereitstellung kann die Häufigkeit der Bereitstellungen so groß sein, dass es schwierig ist, basierend auf der Zeit des Auftretens festzustellen, ob die Bereitstellung den Vorfall verursacht hat.

Ihre Anwendung kann Konfigurationseinstellungen im Datenspeicher oder an einem anderen Ort speichern. Es ist hilfreich, wenn Sie eine Zeitachse mit Konfigurationsänderungen erstellen können, um zu bestimmen, ob eine dieser Zeilen mit dem erhöhten Latenzwert übereinstimmt.

Arbeitslaständerung

Eine Änderung der Arbeitslast kann zu einer erhöhten Latenz führen. Einige Monitoring-Messwerte, die darauf hinweisen können, dass sich die Arbeitslast geändert hat, umfassen Abfragen pro Sekunde sowie die API-Nutzung oder Latenz. Sie können auch auf Änderungen bei Anfrage- und Antwortgrößen prüfen.

Fehler bei Systemdiagnosen

Der Load-Balancer der flexiblen App Engine-Umgebung leitet keine Anfragen mehr an Instanzen weiter, für die Systemdiagnosen fehlschlagen. Dies kann die Last anderer Instanzen erhöhen, was zu einem kaskadierenden Fehler führen kann. Die Nginx-Logs der flexiblen App Engine-Umgebung zeigen Instanzen an, bei denen Systemdiagnosen fehlschlagen. Analysieren Sie Ihre Logs und das Monitoring, um festzustellen, warum die Instanz fehlerhaft wurde, oder konfigurieren Sie die Systemdiagnosen so, dass sie weniger anfällig für vorübergehende Fehler sind. Beachten Sie, dass eine kurze Verzögerung auftritt, bevor der Load-Balancer den Traffic nicht mehr an eine fehlerhafte Instanz weiterleitet. Diese Verzögerung kann zu einem Fehleranstieg führen, wenn der Load-Balancer keine Anfragen wiederholen kann.

In der App Engine-Standardumgebung werden keine Systemdiagnosen verwendet.

Arbeitsspeicherdruck

Wenn das Monitoring entweder ein Sägezahnmuster in der Speichernutzung oder einen Rückgang der Speichernutzung zeigt, der mit Bereitstellungen korreliert, können Leistungsprobleme durch ein Speicherleck verursacht werden. Ein Speicherleck kann zu einer häufigen automatischen Speicherbereinigung führen, was zu einer höheren Latenz führt. Das Problem kann durch die Bereitstellung größerer Instanzen mit mehr Speicher behoben werden, wenn es sich nicht leicht auf ein Problem im Code zurückführen lässt.

Ressourcenleck

Wenn eine Instanz Ihrer Anwendung eine zunehmende Latenz aufweist, die mit dem Alter der Instanz korreliert, kann dies an einem Ressourcenleck liegen, das zu Leistungsproblemen führt. Bei dieser Art von Problem sinkt auch die Latenz direkt nach der Bereitstellung. Beispielsweise kann eine Datenstruktur, die aufgrund einer höheren CPU-Auslastung im Laufe der Zeit langsamer wird, dazu führen, dass jede CPU-gebundene Arbeitslast langsamer wird.

Codeoptimierung

Möglichkeiten zur Optimierung von Code in App Engine, um die Latenz zu reduzieren:

  • Offline-Arbeit: Verwenden Sie Cloud Tasks, damit Nutzeranfragen nicht auf den Abschluss von Arbeitslasten wie dem Senden von E-Mails warten.

  • Asynchrone API-Aufrufe: Achten Sie darauf, dass Ihr Code nicht blockiert wird, bis ein API-Aufruf abgeschlossen ist. Bibliotheken wie ndb bieten eine integrierte Unterstützung dafür.

  • Batch-API-Aufrufe: Die Batch-Version von API-Aufrufen ist normalerweise schneller als das Senden einzelner Aufrufe.

  • Datenmodelle denormalisieren: Reduzieren Sie die Latenz von Aufrufen an die Datenpersistenzebene, indem Sie Ihre Datenmodelle denormalisieren.

Abhängigkeiten

Sie können Abhängigkeiten Ihrer Anwendung überwachen, um zu erkennen, ob Latenzspitzen mit einem Abhängigkeitsfehler korrelieren.

Eine Erhöhung der Latenz einer Abhängigkeit kann durch eine Änderung der Arbeitslast sowie durch einen Anstieg des Traffics verursacht werden.

Nicht skalierende Abhängigkeit

Wenn Ihre Abhängigkeit nicht skaliert wird, wenn die Anzahl der App Engine-Instanzen vertikal skaliert wird, kann die Abhängigkeit überlastet werden, wenn der Traffic zunimmt. Ein Beispiel für eine Abhängigkeit, die möglicherweise nicht skaliert wird, ist eine SQL-Datenbank. Eine höhere Anzahl von Anwendungsinstanzen führt zu einer höheren Anzahl von Datenbankverbindungen, was zu kaskadierenden Fehlern führen kann, da der Start der Datenbank verhindert wird.

Eine Möglichkeit zur Wiederherstellung:

  1. Eine neue Standardversion bereitstellen, die keine Verbindung zur Datenbank herstellt.
  2. Vorherige Standardversion abschalten.
  3. Eine neue, nicht standardmäßige Version bereitstellen, die eine Verbindung zur Datenbank herstellt.
  4. Nach und nach Traffic zur neuen Version migrieren.

Eine mögliche vorbeugende Maßnahme besteht darin, Ihre Anwendung so zu entwerfen, dass Anfragen an die Abhängigkeit mithilfe von adaptivem Throttling gesendet werden.

Ausfall der Caching-Ebene

Eine gute Möglichkeit zur Beschleunigung von Anfragen ist die Verwendung mehrerer Caching-Ebenen:

  • Edge-Caching
  • Memcache
  • Instanzinterner Speicher

Ein plötzlicher Anstieg der Latenz kann durch einen Fehler in einer dieser Caching-Ebenen verursacht werden. Ein Memcache-Flush kann beispielsweise dazu führen, dass mehr Anfragen an den langsameren Datenspeicher gesendet werden.