In diesem Dokument wird erläutert, wie Sie die Auswirkungen von Jobfehlern bei großen Batchpipelines minimieren können. Ausfälle bei großen Arbeitslasten sind besonders schädlich, da die Wiederherstellung und Behebung solcher Probleme viel Zeit und Geld kostet. Wenn diese Pipelines fehlschlagen, ist es sowohl zeitaufwendig als auch teuer, sie von Grund auf neu zu starten.
Folgen Sie den Richtlinien auf dieser Seite, um teure Batch-Pipelinefehler zu vermeiden. Da ausgefallene Elemente und Pipelineausfälle nicht immer vollständig vermieden werden können, konzentrieren sich die hier vorgestellten Techniken darauf, die Resilienz zu erhöhen, die Kosten von Ausfällen zu senken und die Fehlerbehebung und Fehleranalyse zu erleichtern.
Allgemeine Best Practices für Pipelines finden Sie unter Best Practices für Dataflow-Pipelines.
Begrenzte Tests für große Jobs ausführen
Bevor Sie einen großen Batchjob ausführen, sollten Sie einen oder mehrere kleinere Jobs für eine Teilmenge des Datasets ausführen. Mit dieser Methode lässt sich sowohl eine Kostenschätzung erstellen als auch potenzielle Fehlerquellen finden.
Kostenschätzung
Durch das Ausführen von Tests kann ein geschätzter Mindestbetrag für die Gesamtkosten des Jobs ermittelt werden. Normalerweise ist die Kalkulation für die Jobkosten cost of test
job*size(full dataset)/size(test dataset). Je nach Pipeline können die Kosten superlinear oder (seltener) sublinear skaliert werden. Dennoch bietet dieser Schritt oft eine gute grobe Schätzung der Kosten. Sie können auch verschiedene Eingabegrößen ausprobieren, um eine bessere Schätzung der Kosten zu erhalten. Anhand dieser Informationen können Sie entscheiden, ob Sie die vorhandene Pipeline beibehalten oder neu konzipieren, um Kosten zu senken.
Schwachstellen finden
Durch das Ausführen von Tests können Fehler, potenzielle Fehlerquellen oder potenzielle Konfigurations- und Effizienzprobleme aufgedeckt werden. Sie können auch andere Pipeline-Messwerte untersuchen, z. B. die folgenden:
- Wenn Ihre Pipeline fast den gesamten verfügbaren Speicher verwendet, kann es bei höherer Last oder bei außergewöhnlich großen Datensätzen zu OOM-Ausnahmen (Out-of-Memory) kommen. Möglicherweise müssen Sie mehr Arbeitsspeicher für Ihren endgültigen Job bereitstellen, um diese OOM-Fehler zu vermeiden.
- Wenn bei Ihrer Pipeline der Durchsatz einbricht, prüfen Sie die Pipelineprotokolle, um die Ursache zu ermitteln. Möglicherweise finden Sie ein Element, das nicht weiterkommt, oder einen Teil Ihres Datasets mit besonders schlechter Leistung. Sie können diese Datenpunkte separat verarbeiten oder ein Zeitlimit für die Verarbeitung von Elementen erzwingen. Weitere Informationen finden Sie in diesem Dokument im Abschnitt Zeitüberschreitung bei teuren Datensätzen.
- Wenn Ihre Pipeline bei einer Aufgabe in Dataflow viel schlechter abschneidet als lokal, untersuchen Sie die Pipeline-Logik, um die Ursache zu ermitteln. Wenn Sie beispielsweise mit acht Kernen in Dataflow denselben Durchsatz erzielen wie mit einem Kern lokal, besteht bei dem Job möglicherweise ein Engpass aufgrund eines Ressourcenkonflikts. Wenn die Leistung schlechter als erwartet ist, sollten Sie eine oder mehrere der folgenden Optionen in Betracht ziehen:
- Führen Sie weitere Tests mit verschiedenen Computer- oder Softwarekonfigurationen durch.
- Führen Sie dabei lokale Tests mit mehreren Kernen gleichzeitig aus.
- Prüfen Sie Ihren Code auf potenzielle Engpässe bei Bereitstellungen im großen Maßstab.
Wenn Ihre Pipeline Dataflow-Empfehlungen enthält, folgen Sie diesen, um die Leistung zu verbessern.
Dead-Letter-Warteschlangen verwenden, um unerwartete fehlerhafte Daten zu verarbeiten
Pipelines funktionieren häufig bei den meisten Eingabeelementen, schlagen aber bei einer kleinen Teilmenge der Eingabe fehl. Bei kleinen Tests wird dieses Problem möglicherweise nicht erkannt, da nur eine Teilmenge der Eingabe getestet wird. Standardmäßig versucht Dataflow, diese fehlgeschlagenen Aufgaben im Batchmodus viermal und im Streamingmodus unbegrenzt zu wiederholen. Im Batchmodus schlägt der gesamte Job fehl, sobald das Wiederholungslimit erreicht wurde. Im Streamingmodus kann er auf unbestimmte Zeit verzögert werden.
Bei vielen Jobs können Sie diese fehlerhaften Elemente aus der Pipeline ausschließen und den Rest des Jobs mithilfe einer Dead-Letter-Warteschlange (Warteschlange für unverarbeitete Nachrichten) beenden. Die Dead-Letter-Warteschlange leitet fehlgeschlagene Datensätze an eine separate Ausgabe PCollection weiter, die Sie getrennt von Ihrer Hauptausgabe verwalten können. Mit dieser Konfiguration können Sie eine Richtlinie für diese Datensätze entwerfen. Sie können sie beispielsweise manuell in Pub/Sub schreiben, prüfen und bereinigen und dann noch einmal verarbeiten.
Viele Apache Beam-Transformationen bieten integrierte Unterstützung für Dead-Letter-Warteschlangen.
In Java können Sie mit einem ErrorHandler-Objekt auf diese zugreifen. In Python können Sie über die with_exception_handling-Methode auf sie zugreifen. Für einige Transformationen gibt es benutzerdefinierte Möglichkeiten, Dead-Letter-Warteschlangen zu definieren. Weitere Informationen finden Sie in der Dokumentation der Transformation. Weitere Informationen finden Sie unter Dead-Letter-Warteschlangen zur Fehlerbehandlung verwenden.
Im Abschnitt Einschränkungen in diesem Dokument finden Sie Informationen dazu, ob Ihr Job die Kriterien für eine Dead-Letter-Warteschlange erfüllt.
Einschränkungen für Dead-Letter-Warteschlangen
In folgenden Fällen ist eine Dead-Letter-Warteschlange möglicherweise nicht hilfreich:
- Full Worker- oder Lebenszyklus-Probleme.
DoFnWenn die Verarbeitung für den gesamten Worker oder das gesamte Bundle fehlschlägt, kann das Problem nicht von einer Dead-Letter-Warteschlange abgefangen werden. Wenn in Ihrer Pipeline beispielsweise eine OOM-Ausnahme (Out-of-Memory) auftritt, werden alle aktiven Aufgaben auf der VM als fehlgeschlagen eingestuft und noch einmal ausgeführt, ohne dass etwas an die Dead-Letter-Warteschlange gesendet wird. - Kombinationen oder andere Aggregationen. Wenn in Ihrer Pipeline Berechnungen ausgeführt werden, für die alle Eingabeelemente vorhanden und als Teil des Ergebnisses verarbeitet werden müssen, sollten Sie Vorsichtig sein, falls Sie vor diesem Schritt eine Dead-Letter-Warteschlange nutzen. Durch die Nutzung einer Dead-Letter-Warteschlange werden einige Eingabedaten vom Ergebnis ausgeschlossen. Wenn Sie eine Dead-Letter-Warteschlange hinzufügen, kann dies zu geringerer Korrektheit, aber einer höheren Fehlertoleranz führen.
- Fehler auf dem Pfad der Dead-Letter-Warteschlange Wenn ein Element beim Senden an die Senke der Dead-Letter-Warteschlange fehlschlägt, kann die gesamte Pipeline fehlschlagen.
Um dieses Problem zu vermeiden, sollten Sie die Logik der Dead-Letter-Warteschlange so einfach wie möglich halten. Sie können einen Warteschritt hinzufügen (siehe
wait class), damit die Haupteingabe abgeschlossen wird, bevor die Elemente der Dead-Letter-Warteschlange geschrieben werden. Diese Konfiguration kann die Leistung beeinträchtigen und Fehlersignale aus der Pipeline verzögern. - Teilweise transformierte Elemente: Wenn Sie eine Dead-Letter-Warteschlange in die Mitte Ihrer Pipeline einfügen, gibt diese möglicherweise das teilweise transformierte Element aus und hat keinen Zugriff auf das ursprüngliche Element. Entsprechend können Sie das Element nicht bereinigen und die Pipeline nicht noch einmal dafür ausführen. Stattdessen werden Sie möglicherweise eine andere Logik anwenden müssen, um die Ausgabe in der Dead-Letter-Warteschlange mit dem ursprünglichen Element in Beziehung zu setzen, oder Sie müssen das teilweise transformierte Element interpretieren und verarbeiten. Außerdem kann dies zu inkonsistenten Ergebnissen führen. Wenn Elemente beispielsweise durch zwei Zweige einer Pipeline gesendet werden und jeder Zweig Elemente, die zu Ausnahmen führen, an eine Dead-Letter-Warteschlange sendet, kann ein einzelnes Eingabeelement einen, den anderen, beide oder keinen der Zweige passieren.
Teure Datensätze ausblenden
Pipelines reagieren möglicherweise nicht mehr, wenn eine kleine Teilmenge von Elementen verarbeitet wird, die teurer sind oder eine Einschränkung aufweisen, die zu einer Reaktionslosigkeit führt, z. B. ein Deadlock. Um dieses Problem zu beheben, können Sie für einige Transformationen ein Zeitlimit festlegen und die Elemente mit Zeitüberschreitung in allen DoFns mit Nutzercode, bei denen dieses Problem auftritt, als fehlgeschlagen markieren. Sie können beispielsweise die with_exception_handling-Methode von Python verwenden. Wenn Sie Zeitüberschreitungen mit einer Dead-Letter-Warteschlange verwenden, kann Ihre Pipeline weiterhin fehlerfreie Elemente verarbeiten und Fortschritte erzielen. Die aufwendigen Elemente können Sie separat noch einmal verarbeiten. Diese Konfiguration kann sich negativ auf die Leistung auswirken.
Um festzustellen, für welche DoFn-Vorgänge wahrscheinlich ein Zeitlimit erforderlich ist, führen Sie begrenzte Tests aus, bevor Sie die vollständige Pipeline starten.
Vertikales Autoscaling aktivieren
Wenn Sie nicht sicher sind, wie viel Arbeitsspeicher Ihr Job benötigt, oder der Meinung sind, dass der für den Job bereitgestellte Arbeitsspeicher nicht ausreichen könnte, aktivieren Sie das vertikale Autoscaling. Diese Funktion hilft, OOM-Fehler zu vermeiden, wenn Pipelines in größerem Umfang ausgeführt werden oder außergewöhnlich große Elemente enthalten.
Da vertikales Autoscaling die Kosten Ihres Jobs erhöhen kann und nicht alle OOM-Fehler verhindert, müssen Sie weiterhin Probleme mit übermäßigem Speicherverbrauch beheben. Für vertikales Autoscaling ist auch Dataflow Prime erforderlich, das zusätzliche Einschränkungen und ein anderes Abrechnungsmodell hat.
Spekulative Ausführung verwenden, um Nachzügler zu vermeiden
Für Batch-Pipelines können Sie die spekulative Ausführung aktivieren, um die Auswirkungen von langsam laufenden oder hängenden Aufgaben zu minimieren. Diese langsamen oder hängenden Aufgaben werden auch als Nachzügler bezeichnet. Mit dieser Funktion werden redundante oder Backup-Ausführungen von Aufgaben gestartet, die zu lange dauern. Die erste Aufgabe, die abgeschlossen wird, wird verwendet und die andere wird abgebrochen. Dadurch kann die Gesamtdauer Ihrer Pipeline verkürzt werden.
Die spekulative Ausführung kann dazu beitragen, dass Pipelines schneller abgeschlossen werden. Dazu wird ein alternativer Ausführungspfad für Arbeitselemente bereitgestellt, die aufgrund langsamer Worker-Maschinen oder anderer vorübergehender Probleme wie nicht deterministischer Fehler, Ressourcenbegrenzung oder Verbindungsprobleme verzögert werden.
Einschränkungen und Überlegungen
Bevor Sie die spekulative Ausführung aktivieren, sollten Sie Folgendes berücksichtigen:
- Streaming-Pipelines:Die spekulative Ausführung wird für Streaming-Pipelines nicht unterstützt.
- Mögliche Kostenänderung: Die Kostenauswirkungen dieser Funktion sind schwer zu schätzen, da Nachzügler und die Bereitstellung von Sicherungsaufgaben schwer vorherzusagen sind. Ein Backup-Arbeitselement verbraucht beispielsweise zusätzliche Ressourcen, was die Kosten potenziell erhöht. Die frühere Fertigstellung kann jedoch umgekehrt zu Ressourceneinsparungen und Kostensenkungen führen. In beiden Fällen dürften die Auswirkungen insgesamt minimal sein.
- Konsistente, lang andauernde Arbeitsvorgänge: Die spekulative Ausführung kann bei konsistenten, lang andauernden Arbeitsvorgängen wie Hotkeys nicht wesentlich helfen, da das zugrunde liegende Problem, das die Verlangsamung verursacht, weiterhin besteht.
Weitere Informationen zu Nachzüglern in Batchjobs finden Sie unter Fehlerbehebung bei Nachzüglern in Batchjobs.
Spekulative Ausführung aktivieren
Verwenden Sie die Dataflow-Dienstoption map_task_backup_mode, um die spekulative Ausführung zu aktivieren. Es gibt zwei Modi:
Java
--dataflowServiceOptions=map_task_backup_mode=ON--dataflowServiceOptions=map_task_backup_mode=CAUTIOUS
Python / Go
--dataflow_service_options=map_task_backup_mode=ON--dataflow_service_options=map_task_backup_mode=CAUTIOUS
Im Modus ON wird eine Sicherungsaufgabe geplant, wenn die erwartete Laufzeit der ursprünglichen Aufgabe etwa 20% länger ist als die erwartete Laufzeit einer neuen Aufgabe.
Im CAUTIOUS-Modus wird eine Sicherungsaufgabe geplant, wenn die erwartete Laufzeit der ursprünglichen Aufgabe etwa 70% länger ist als die erwartete Laufzeit einer neuen Aufgabe.
Prüfen Sie die Log-Nachrichten, um zu bestätigen, dass die spekulative Ausführung aktiviert ist. Suchen Sie nach Einträgen, die zeigen, dass Sicherungsaufgaben gestartet wurden. Damit wird bestätigt, dass die spekulative Ausführung ausgelöst wird. Wenn Sie sich diese Logs ansehen möchten, rufen Sie das Feld Job-Logs für Ihre Pipeline auf (Jobs > wählen Sie Ihren Job aus > Bereich „Logs“ > Job-Logs). Die Logmeldung sieht so aus:
Backup issued in step STEP_NAME. ADDITIONAL_INFORMATION.
Problemumgehungen für fehleranfällige Pipelines
Bei einigen Pipelines treten besonders häufig Fehler auf. Es ist zwar besser, die Ursache dieser Fehler zu beheben, aber Sie können die Kosten für Ausfälle auch auf folgende Arten senken.
Zwischenergebnisse erfassen
Pipelines können eine oder mehrere besonders rechenintensive Transformationen enthalten, die die Ausführungszeit der Pipeline dominieren. Pipelinefehler nach dieser Transformation können besonders schädlich sein, da die gesamte bereits erledigte Arbeit verloren geht. Um dieses Szenario zu vermeiden, sollten Sie durch teure Schritte generierte, zwischenzeitliche PCollectionss in eine Senke wie Cloud Storage schreiben. Diese Konfiguration reduziert die Kosten eines Fehlers. Sie müssen diesen Vorteil gegen die Kosten für den zusätzlichen Schreibvorgang abwägen. Sie haben folgende Möglichkeiten, ein solches materialisiertes Ergebnis zu verwenden:
- Teilen Sie die ursprüngliche Pipeline in zwei Pipelines auf: eine, die das Zwischenergebnis schreibt, und eine, die es liest.
- Lesen sie ausschließlich bei Pipelineausfällen Ergebnisse sowohl aus der ursprünglichen Quelle als auch aus der materialisierten Zwischensammlung und verflachen Sie diese.
Damit diese Materialisierungen vor der weiteren Verarbeitung geschrieben werden, fügen Sie vor allen nachfolgenden Verarbeitungsschritten einen Warteschritt ein (siehe wait
class).