Im dynamischen Web-Ökosystem werden Systeme zunehmend umfassender und verteilter, wodurch die Bedeutung von Observability, Automatisierung und robusten Test-Frameworks steigt. Eine Spitzenrolle beim Aufbau widerstandsfähiger Systeme nimmt das Chaos Engineering ein, eine Methode, bei der absichtlich Fehler in das System eingebracht werden, um Schwachstellen zu identifizieren, bevor sie zu echten Problemen führen. New Relic führt wöchentlich Chaosexperimente in unserer Vorproduktionsumgebung durch, um potenzielle Systemausfälle aufzudecken und zu beheben, insbesondere in komplexen Umgebungen wie relationalen Datenbanken.

Besondere Herausforderungen stellen sich bei Amazon Aurora und andere Datenbanken aufgrund ihrer verteilten Natur, ihrer Architektur und Failover-Methode bei der Bereitstellung hoher Verfügbarkeit. In diesem Beitrag erfahren Sie, wie Sie Observability und Chaos Engineering nutzen können, um sicherzustellen, dass Ihre Dienste Datenbank-Verschlechterungen bewältigen können.

Chaos Testing für Datenbanken

Chaostests bieten unschätzbare Einblicke in die Systemresilienz und bereiten Teams auf reale Szenarien vor. Hier sind die wichtigsten Vorteile von Chaostests auf Datenbankebene:

  • Validieren Failover und Anwendungsrobustheit: Schwachstellen bei der Anwendungsfehlerbehandlung und Treiberkonfiguration werden aufgezeigt und es bietet sich die Möglichkeit, den Systemschutz zu verstärken.

  • Mildern potenzielle Ausfälle und schützen Daten: Regelmäßige Chaosexperimente reduzieren Überraschungen, minimieren Ausfälle und schützen vor Datenverlust, indem sie die Incident-Response-Zeit verbessern.

  • Sorgen für Effektivität bei Observability und Alerting: Chaos-Szenarien testen unsere Monitoring-Infrastruktur und Alerting-Mechanismen und ermöglichen den Teams, ihre Incident-Response-Strategie zu verfeinern.

  • Vertiefen das Systemverständnis und verbessern die Dokumentation: Teams erweitern ihr Wissen und erstellen eine durchdachte Dokumentation, die das zukünftige Fehlerbehebungs- und Incident Management unterstützt.

  • Optimieren Kapazität und Performance: Chaostests bringen Belastungspunkte und Kapazitätsgrenzen ans Licht und helfen Teams dabei, ihre Infrastruktur besser zu planen und zu skalieren.

Erste Schritte

Für erfolgreiches Chaos Testing müssen zunächst Observability und Monitoring eingerichtet werden. Nachfolgend erläutern wir die Hauptkomponenten im Detail:

New Relic Go Agent für APM: New Relic für Go überwacht Ihre Go-Sprachanwendungen und -Microservices, um Ihnen bei der Erkennung und Behebung von Performance-Problemen zu helfen.

Durch die Integration dieser Komponenten in Ihre Cloud-Architektur können Sie den Grundstein für eine detaillierte Observability legen, die für die Durchführung von Chaosexperimenten und das Lernen daraus von entscheidender Bedeutung ist.

Vorbereitung der Datenbank auf Observability

Es ist wichtig, Systemänderungen aktiv zu beobachten, anstatt sie nur zu sehen – also durch automatisiertes Monitoring, das Rohdaten in umsetzbare Erkenntnisse umwandelt, ihren Kontext und ihre Auswirkungen im Zeitverlauf zu verstehen.

Clientseitig

Die Überwachung des Anwendungsverhaltens bei der Interaktion mit der Datenbank ist unverzichtbar. Verwenden Sie New Relic APM zum Application Performance Monitoring in Echtzeit für das Monitoring folgender Aspekte:

  • Fehlerquote: Überwachen Sie die Fehlerhäufigkeit in der Anwendung während des Chaosexperiments.

  • Throughput: Behalten Sie die Anzahl der Transaktionen im Auge, die Ihre Anwendung verarbeitet.

  • Antwortzeit: Messen Sie, wie lange es dauert, bis Ihre Anwendung in verschiedenen Testphasen auf Anfragen reagiert.

  • Alerting: Konfigurieren Sie Alerts für Anomalien in Fehlerquoten und Throughput, um eine schnelle Reaktion auf Probleme zu ermöglichen, die eventuell beim Chaostest aufgedeckt werden.

Serverseitig

Auf der anderen Seite ist es ebenso notwendig zu überwachen, was im Datenbankdienst selbst passiert. Folgendes sollten Sie im Auge behalten:

  • CloudWatch-Aurora-Metriken: Nutzen Sie Amazon CloudWatch, um KPIs für Aurora zu verfolgen, einschließlich CPU-Auslastung, Ein-/Ausgabevorgänge pro Sekunde (IOPS) und mehr.

  • Datenbanklogs: Managen Sie die Datenbank-Logdaten und untersuchen Sie die Ergebnisse von Aurora, um ungewöhnliche Muster oder Probleme zu identifizieren, die beim Test serverseitig festgestellt wurden.

  • Throughput-Analyse: Vergleichen Sie den Throughput vor, während und nach dem Chaostest, um seine Auswirkungen auf die Performance zu verstehen.

Durch die Verknüpfung anwendungsseitiger Daten von New Relic APM mit CloudWatch-Metriken erreichen wir eine vielschichtige Ansicht, die für die Durchführung von Chaosexperimenten und deren maximaler Ausschöpfung von entscheidender Bedeutung ist.

Denken Sie daran: Observability ist keine bloße Checkliste, die es abzuhaken gilt – es geht darum, strategisch zu entscheiden, was gemessen werden soll, das richtige Alerting einzurichten und zu verstehen, wie uns die Daten im gesamten Stack die Einblicke geben, die wir für Hypothesen, Validierungen und Iterationen benötigen.

Ausführen eines Aurora-Failovers

Failover ist ein wichtiges Verfahren zur Aufrechterhaltung der Datenverfügbarkeit bei unerwarteten Störungen. Der Failover-Prozess von Amazon Aurora ist darauf ausgelegt, Downtime zu minimieren, indem Datenbankvorgänge automatisch an eine Standby-Instanz umgeleitet werden. Wenn Sie diesen Vorgang verstehen, können Sie Ihre Systeme auf Ausfallsicherheit vorbereiten.

Hier ist eine kurze Aufschlüsselung dessen, was während eines Aurora-Failovers passiert:

  1. Instanzauswahl: Aurora wählt eine geeignete Reader-Instanz zur Höherstufung in den Primärstatus aus. Die Auswahl berücksichtigt die Spezifikationen der Instanz, ihre Verfügbarkeitszone und vordefinierte Failover-Prioritäten. Für einen detaillierten Einblick in diesen Prozess stellt AWS im Abschnitt zur Hochverfügbarkeit für Amazon Aurora umfassende Details bereit.

  2. Höherstufung der Instanz: Die ausgewählte Reader-Instanz wird im Lese-/Schreibmodus neu gestartet, um als neue primäre Instanz zu dienen.

  3. Herabstufung der primären Instanz: Gleichzeitig wird der alte primäre Knoten im schreibgeschützten Modus neu gestartet und für die Aufnahme in den Pool der Reader-Instanzen vorbereitet.

  4. DNS-Endpunkt-Updates: Um die neuen Rollen widerzuspiegeln, aktualisiert Aurora seine DNS-Einträge. Der Writer-Endpunkt verweist auf die neue primäre Instanz, während der Reader-Endpunkt den alten primären Knoten in seiner Liste der Reader aggregiert. Die DNS-Änderung verwendet eine Time-to-Live(TTL)-Konfiguration von 5 Sekunden, aber clientseitiges Caching hat Einfluss darauf, wie schnell diese Änderung erkannt wird.

Während des Failover-Übergangs ist mit kurzen Verbindungsunterbrechungen zu rechnen. Es kann zu einigen Sekunden Unterbrechung kommen, während Aurora den Verkehr auf den neuen WRITER umleitet und die READER-Einstellungen anpasst. Normalerweise dauern diese Unterbrechungen etwa 5 Sekunden, wie aus den von AWS für Failover dokumentierten Beobachtungen hervorgeht.

Um ein reibungsloses Failover zu ermöglichen, müssen unsere Anwendungen und Treiber darauf abgestimmt sein, diese Übergänge nahtlos zu bewältigen. In den folgenden Abschnitten besprechen wir die Treiberkonfiguration und die optimalen Einstellungen für Ihre Clientanwendungen, um diese Übergänge mit minimalen Auswirkungen zu bewältigen.

Identifizieren und Beheben von Treiberproblemen

Monitoring im Hinblick auf Treiber- und Systemfehler trägt wesentlich zum Verständnis bei, wie Ihre Anwendung ein Datenbank-Failover übersteht. Achten Sie auf Ihre clientseitigen APM-Fehler und die in Logs aufgezeichneten serverseitigen Datenbankfehler, um Anzeichen für Fehler im Zusammenhang mit dem Schreiben in eine Reader-/Replica-Rolle zu erkennen.

APM und Log-Events

Hier sind einige Beispiele für Fehler, die auftreten können, wenn eine MySQL- oder PostgreSQL-Datenbank während eines Failovers in den schreibgeschützten Zustand wechselt, was darauf hinweist, dass die Anwendung einen unzulässigen Schreibvorgang versucht hat:

PostgreSQL:

nested exception is org.postgresql.util.PSQLException: 
ERROR: cannot execute nextval() in a read-only transaction

MySQL:

Error 1290 (HY000): The MySQL server is running with the 
--read-only option so it cannot execute this statement

In Go geschriebene MySQL-Anwendungen loggen möglicherweise Fehler, die den schreibgeschützten Charakter der Datenbank nach einem Failover hervorheben:


Error 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
                                                                               main.(*Env).execQueryHandler (/src/handlers.go:204)
                                                             http.HandlerFunc.ServeHTTP (/usr/local/go/src/net/http/server.go:2136)
…in.configureServer.WrapHandleFunc.WrapHandle.func19 (/src/vendor/github.com/newrelic/go-agent/v3/newrelic/instrumentation.go:98)
                                                             http.HandlerFunc.ServeHTTP (/usr/local/go/src/net/http/server.go:2136)
          main.configureServer.WrapHandleFunc.func10 (/src/vendor/github.com/newrelic/go-agent/v3/newrelic/instrumentation.go:184)
                                                             http.HandlerFunc.ServeHTTP (/usr/local/go/src/net/http/server.go:2136)
                                                           mux.(*Router).ServeHTTP (/src/vendor/github.com/gorilla/mux/mux.go:212)
                                                             http.(*ServeMux).ServeHTTP (/usr/local/go/src/net/http/server.go:2514)
                                                           http.serverHandler.ServeHTTP (/usr/local/go/src/net/http/server.go:2938)
                                                                     http.(*conn).serve (/usr/local/go/src/net/http/server.go:2009)
                                                                        runtime.goexit (/usr/local/go/src/runtime/asm_amd64.s:1650)

Bei einer fehlerhaften Treiberkonfiguration kann die Fehlerquote nach dem Failover auf unbestimmte Zeit hoch bleiben, was hier bei New Relic APM zu sehen ist:

Die schnelle Identifizierung dieser Fehlermeldungen ist für eine rasche Incident Response von entscheidender Bedeutung. Unabhängig davon, ob Sie New Relic APM zum Analysieren der Anwendungs-Performance verwenden oder detailliertere Logdaten durchgehen, kann es bei Ihrem Troubleshooting sehr hilfreich sein, während und nach einem Failover auf diese Fehlermuster zu achten.

Treiberkonfiguration und Best Practices

Datenbankverbindungstreiber müssen richtig eingestellt sein, um Failovers für geplante Wartungsvorgänge und auch für ungeplante Szenarien zu handhaben.

Treiberkonfiguration

Um die Störungen durch Failover-Events zu überstehen, müssen Datenbankverbindungstreiber präzise abgestimmt werden. Dies bereitet Ihr System nicht nur auf geplante Wartungsarbeiten vor, sondern schafft auch die Grundlage für die Bewältigung ungeplanter Szenarien.

Folgendes sollten Sie bei der Konfiguration Ihrer Datenbank- und Cache-Treiber beachten:

  • DNS-TTL-Einstellungen: Stellen Sie sicher, dass Ihr Betriebssystem, alle DNS-Managementebenen und der Datenbanktreiber die 5-Sekunden-DNS-TTL-Richtlinie von AWS einhalten.

  • Verwenden Sie intelligente Datenbanktreiber: Entscheiden Sie sich für Treiber, die das DNS-Caching effektiv verwalten und Instanzen für eine automatische Wiederverbindung überwachen, wenn sich der Primärstatus ändert.

  • Legen Sie Treiberoptionen fest: Ziehen Sie für AWS-Datenbanken den spezialisierten JDBC-Treiber für MySQL und den JDBC-Treiber für PostgreSQL in Betracht. Wenn keine intelligenten Treiber verfügbar sind, verwalten Sie die Einstellungen für die Verbindungslebensdauer, um sicherzustellen, dass Verbindungen im Einklang mit der DNS-TTL erneuert werden.

Konfigurieren Sie die maximale Verbindungslebensdauer: Ohne die Option für einen intelligenten Datenbanktreiber gibt es die Alternative, Ihren Connection-Pooler so zu konfigurieren, dass er für jede Verbindung eine maximale Lebensdauer hat. Nach Ablauf eines festgelegten Zeitraums X muss sie geschlossen und dann wiederhergestellt werden. Eine solche Einstellung trägt dazu bei, die DNS-Vorgaben einzuhalten.

Beispiel für die Konfiguration eines Go-Diensttreibers:

// Konfigurationseinstellungen für DB-Treiber. DB-Treiberkonfiguration und Verhalten von
// Connection-Pool anpassen, siehe: https://go.dev/doc/database/manage-connections
// Gesamtzahl der Verbindungen begrenzen, für die diese App-Instanz
// auf dem Datenbankserver verwendet werden kann.
db.SetMaxOpenConns(10)
 // Anzahl der aufrechterhaltenen Leerlaufverbindungen begrenzen.
db.SetMaxIdleConns(3)
// Verbindungen regelmäßig wiederherstellen, damit RW-Failover innerhalb von 1 Min. durchgeführt werden.
db.SetConnMaxLifetime(60 * time.Second)
 // Leerlaufverbindungen nach 30 Sek. Inaktivität schließen.
db.SetConnMaxIdleTime(30 * time.Second)

Observability, Metriken und Alerts

In der chaotischen Umgebung von Failover-Experimenten liefert effektive Observability die nötige Transparenz. Strukturiertes Monitoring und Alerting sorgen dafür, dass Sie stets informiert und handlungsbereit sind.

  • New Relic APM: Hilft Ihnen, die Clientseite zu verstehen. Was erkennt die Anwendung hinsichtlich ihrer eigenen Aktivitäten gegenüber dem Datenbankserver? Wie hoch waren Antwortzeit, Throughput und Fehlerquote?

  • Infrastructure Agent mit Integrationen für Datenbanken: Überwacht die Performance Ihres Systems. Umfasst spezielle Integrationen für MySQL sowie PostgreSQL und bietet Einblicke speziell zu diesen Datenbanken.

  • New Relic Amazon CloudWatch Metric Streams mit Kinesis Firehose: Nutzen Sie die Metric Streams, um einen kontinuierlichen Fluss von CloudWatch-Metriken an New Relic zu senden, einschließlich Echtzeit-Monitoring-Daten für Aurora-Datenbanken.

  • Alerting: Richten Sie die entsprechenden Alerts für Ihre Situation ein. Starke Kandidaten sind oft Fehlerquote, Throughput und Antwortzeit. In Failover-Situationen ist insbesondere die Fehlerquote wichtig, aber Schreib-Throughput- und Antwortzeiten-Monitoring können in vielen Situationen zusätzlichen Nutzen bringen.

Diese Fehlerquote stellt die positive Erfahrung innerhalb einer Minute dar.

Zukünftige Chaosexperimente

Während Sie Ihre Resilienzstrategien weiter verfeinern, können Umfang und Komplexität Ihrer Chaosexperimente zunehmen. Dazu gehören die Erkundung neuer Dienste, der Auswirkungen unterschiedlicher Skalierungs- und Lastmuster sowie komplexere Fehlersimulationen.