Best Practices für Pipelines mit großen Batches

In diesem Dokument wird beschrieben, wie Sie die Auswirkungen von Jobausfällen bei großen Batch-Pipelines minimieren. 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 bei einem Fehler von vorn gestartet werden müssen, ist das sowohl zeit- als auch kostenintensiv.

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.

Bevor Sie einen großen Batchjob ausführen, sollten Sie einen oder mehrere kleinere Jobs für einen Teil des Datasets ausführen. Diese Methode kann sowohl eine Kostenschätzung liefern als auch helfen, potenzielle Fehlerquellen zu finden.

Kostenschätzung

Durch Tests können Sie einen geschätzten Mindestwert für die Gesamtkosten des Jobs ermitteln. 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 liefert dieser Schritt oft eine gute grobe Schätzung der Arbeitskosten. 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 mit der vorhandenen Pipeline fortfahren oder Ihre Pipeline neu strukturieren möchten, um die Kosten zu senken.

Schwachstellen finden

Durch Tests können Bugs, potenzielle Fehlerquellen oder potenzielle Konfigurations- und Effizienzprobleme aufgedeckt werden. Sie können auch andere Pipelinemesswerte prüfen, z. B.:

  • Wenn Ihre Pipeline fast den gesamten verfügbaren Arbeitsspeicher belegt, kann es bei höherer Auslastung oder bei außergewöhnlich großen Einträgen zu OOM-Ausnahmen (Out-of-Memory) kommen. Möglicherweise müssen Sie mehr Arbeitsspeicher für den 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 hängendes Element oder einen Teil Ihres Datensatzes 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 für teure Einträge.
  • Wenn die Leistung Ihrer Pipeline bei einer Aufgabe in Dataflow viel schlechter ist als lokal, prüfen Sie die Pipelinelogik, um den Grund 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 nicht den Erwartungen entspricht, können 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 für Ihre Pipeline Dataflow-Empfehlungen vorliegen, folgen Sie ihnen, um die Leistung zu verbessern.

Dead-Letter-Warteschlangen für die Verarbeitung unerwarteter fehlerhafter Daten verwenden

Pipelines funktionieren häufig bei den meisten Eingabeelementen, schlagen aber bei einer kleinen Teilmenge der Eingabe fehl. Bei kleinen Tests ist das Problem möglicherweise nicht zu erkennen, da bei diesen Tests nur ein Teil der Eingaben getestet wird. Standardmäßig werden diese fehlgeschlagenen Aufgaben im Batchmodus viermal und im Streamingmodus unbegrenzt wiederholt. 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 Einträge an eine separaten Ausgabe-PCollection weiter, die Sie getrennt von Ihrer Hauptausgabe verwalten können. Mit dieser Konfiguration können Sie eine Richtlinie für diese Einträge erstellen. Sie können sie beispielsweise manuell in Pub/Sub schreiben, prüfen und bereinigen und dann die Datensätze 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.DoFn Wenn 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.

Zeitüberschreitung für kostenintensive Einträge

Pipelines reagieren möglicherweise nicht mehr, wenn eine kleine Teilmenge von Elementen verarbeitet wird, die teurer sind oder eine Einschränkung erreichen, die zu einer Nichtreaktion führt, z. B. einen Deadlock. Um dieses Problem zu minimieren, können Sie bei einigen Transformationen ein Zeitlimit festlegen und die Elemente, bei denen das Zeitlimit überschritten wurde, in allen DoFns des Nutzercodes scheitern lassen, bei denen dieses Problem auftritt. 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 kostenintensiven Elemente können Sie separat noch einmal verarbeiten. Diese Konfiguration kann zu Leistungseinbußen führen.

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. Mit dieser Funktion lassen sich OOM-Fehler vermeiden, wenn Pipelines im größeren Maßstab ausgeführt werden oder auf außergewöhnlich große Elemente stoßen.

Da das vertikale Autoscaling die Kosten Ihres Jobs erhöhen und nicht alle Fehler aufgrund von Speichermangel verhindern kann, müssen Sie Probleme mit übermäßiger Speichernutzung weiterhin beheben. Für vertikales Autoscaling ist außerdem Dataflow Prime erforderlich, das zusätzliche Einschränkungen und ein anderes Abrechnungsmodell hat.

Problemumgehungen für fehleranfällige Pipelines

Einige Pipelines sind besonders fehleranfällig. 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 aufwendige Transformationen enthalten, die die Ausführungszeit der Pipeline dominieren. Pipelinefehler nach dieser Transformation können besonders schädlich sein, da alle bereits abgeschlossenen Arbeiten verloren gehen. 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 Ausfalls. Sie müssen diesen Vorteil gegen die Kosten für die zusätzliche Schreibvorgänge abwägen. Sie haben folgende Möglichkeiten, ein solches materialisiertes Ergebnis zu verwenden:

  1. Teilen Sie die ursprüngliche Pipeline in zwei Pipelines auf: eine, die das Zwischenergebnis schreibt, und eine, die es liest.
  2. 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 (siehe wait class) hinzu.