Überwachung von ETL-Prozessen in einem kleinen Datenspeicher

Viele nutzen spezialisierte Werkzeuge zur Erstellung von Prozessen zur Extraktion, Transformation und Speicherung von Daten in relationalen Datenbanken. Die Arbeitsabläufe der Werkzeuge werden protokolliert und Fehler festgehalten.

Im Fehlerfall enthält das Protokoll Informationen darüber, dass das Werkzeug die Aufgabe nicht ausführen konnte und in welchen Modulen (häufig handelt es sich um Java) es zu einem Halt kam. In den letzten Zeilen lässt sich der Datenbankfehler finden, beispielsweise ein Verstoß gegen den einzigartigen Schlüssel der Tabelle.

Um die Rolle der Fehlermeldungen im ETL-Prozess zu erläutern, habe ich alle Probleme, die in den letzten zwei Jahren in einem großen Speicher aufgetreten sind, klassifiziert.

Überwachung von ETL-Prozessen in einem kleinen Datenspeicher

Zu den Datenbankfehlern gehören Probleme wie nicht ausreichender Speicherplatz, unterbrochene Verbindungen, hängende Sessions usw.

Logische Fehler umfassen Dinge wie Verletzungen von Tabellenschlüsseln, ungültige Objekte, fehlender Zugriff auf Objekte usw.
Der Scheduler kann verspätet gestartet werden, hängen bleiben usw.

Einfache Fehler erfordern nicht viel Zeit zur Behebung. Mit den meisten kann ein gutes ETL-System selbstständig umgehen.

Komplexe Fehler erfordern das Öffnen und Überprüfen von Datenverarbeitungsverfahren sowie die Analyse von Datenquellen. Dies führt häufig zu Änderungen und Tests von Deployments.

So hängt die Hälfte aller Probleme mit der Datenbank zusammen. 48 % aller Fehler sind einfache Fehler.
Ein Drittel aller Probleme ist auf Veränderungen in der Logik oder Struktur des Speichers zurückzuführen, wobei mehr als die Hälfte dieser Fehler komplex ist.

Und weniger als ein Viertel aller Probleme betrifft den Aufgabenplaner, von denen 18 % einfache Fehler sind.

Insgesamt sind 22 % aller aufgetretenen Fehler komplex, deren Behebung die meiste Aufmerksamkeit und Zeit erfordert. Sie treten etwa einmal pro Woche auf, während einfache Fehler fast täglich vorkommen.

Offensichtlich wird das Monitoring von ETL-Prozessen dann effektiv sein, wenn der Fehler im Protokoll so genau wie möglich angegeben ist und die Suche nach der Problembquelle minimalen Aufwand erfordert.

Effektives Monitoring

Was hätte ich mir im ETL-Monitoring gewünscht?

Überwachung von ETL-Prozessen in einem kleinen Datenspeicher
Start at — wann der Prozess begonnen hat,
Source — Datenquelle,
Layer — welche Ebene des Speichers geladen wird,
ETL-Job-Name — ein Ladeprozess, der aus vielen kleinen Schritten besteht,
Schritt Nummer — die Nummer des ausgeführten Schrittes,
Betroffene Zeilen — wie viele Daten bereits verarbeitet wurden,
Dauer in Sekunden — wie lange die Ausführung dauert,
Status — ob alles in Ordnung ist oder nicht: OK, ERROR, RUNNING, HANGS
Nachricht — die letzte erfolgreiche Mitteilung oder eine Fehlerbeschreibung.

Basierend auf dem Status der Aufzeichnungen kann eine E-Mail an andere Teilnehmer gesendet werden. Wenn keine Fehler auftreten, ist die E-Mail nicht zwingend erforderlich.

So ist im Falle eines Fehlers der genaue Ort des Vorfalls klar angegeben.

Es kommt manchmal vor, dass das Überwachungstool selbst nicht funktioniert. In diesem Fall besteht die Möglichkeit, direkt in der Datenbank die Ansicht (View) aufzurufen, auf der der Bericht basiert.

ETL-Überwachungstabelle

Um die ETL-Prozesse zu überwachen, genügt eine Tabelle und eine Ansicht.

Dazu kann man zurückgehen zu seinem kleinen Speicher und einen Prototyp in der SQLite-Datenbank erstellen.

DDL-Tabelle

ERSTELLEN SIE DIE TABELLE UTL_JOB_STATUS (
/* Tabelle zur Protokollierung der Jobausführung. Wichtig, dass der Job die Schritte ETL_START und ETL_END oder ETL_ERROR hat */
  UTL_JOB_STATUS_ID INTEGER NICHT NULL PRIMARY KEY AUTOINCREMENT,
  SID               INTEGER NICHT NULL STANDARD -1, /* Sitzungsidentifikator. Einzigartig für jede Ausführung des Jobs */
  LOG_DT            INTEGER NICHT NULL STANDARD 0,  /* Datum und Uhrzeit */
  LOG_D             INTEGER NICHT NULL STANDARD 0,  /* Datum */
  JOB_NAME          TEXT NICHT NULL STANDARD 'N/A', /* Jobname wie JOB_STG2DM_GEO */
  STEP_NAME         TEXT NICHT NULL STANDARD 'N/A', /* ETL_START, ..., ETL_END/ETL_ERROR */
  STEP_DESCR        TEXT,                        /* Beschreibung der Aufgabe oder Fehlermeldung */
  EINDEUTIG (SID, JOB_NAME, STEP_NAME)
);
EINFÜGEN IN UTL_JOB_STATUS (UTL_JOB_STATUS_ID) WERTE (-1);

DDL Ansicht/Bericht

ERSTELLEN SIE DIEANSICHT, WENN NICHT BEREITS VORHANDEN UTL_JOB_STATUS_V
AS /* Inhalt: Ausführungsprotokoll des Pakets für die letzten 3 Monate. */
MIT SRC ALS (
  WÄHLEN SIE LOG_D,
    LOG_DT,
    UTL_JOB_STATUS_ID,
    SID,
	FALLS INSTR(JOB_NAME, 'FTP') DANN 'ÜBERTRAGUNG' /* Dateiübertragung */
	     FÄLLS INSTR(JOB_NAME, 'STG') DANN 'STUFE' /* Stufe */
	     FÄLLS INSTR(JOB_NAME, 'CLS') DANN 'REINIGUNG' /* Reinigung */
	     FÄLLS INSTR(JOB_NAME, 'DIM') DANN 'DIMENSION' /* Dimension */
	     FÄLLS INSTR(JOB_NAME, 'FCT') DANN 'FAKT' /* Fakt */
		 FÄLLS INSTR(JOB_NAME, 'ETL') DANN 'STUFE-MART' /* Datenmart */
	     FÄLLS INSTR(JOB_NAME, 'RPT') DANN 'BERICHT' /* Bericht */
	     ANDERES 'N/A' END AS LAYER,
	FALLS INSTR(JOB_NAME, 'ACCESS') DANN 'ZUGRIFFSPROTOKOLL' /* Quelle */
	     FÄLLS INSTR(JOB_NAME, 'MASTER') DANN 'STAMMDATEN' /* Quelle */
	     FÄLLS INSTR(JOB_NAME, 'AD-HOC') DANN 'AD-HOC' /* Quelle */
	     ANDERES 'N/A' END AS SOURCE,
    JOB_NAME,
    STEP_NAME,
    FALLS STEP_NAME='ETL_START' DANN 1 SONST 0 END AS START_FLAG,
    FALLS STEP_NAME='ETL_END' DANN 1 SONST 0 END AS END_FLAG,
    FALLS STEP_NAME='ETL_ERROR' DANN 1 SONST 0 END AS ERROR_FLAG,
    STEP_NAME || ' : ' || STEP_DESCR AS STEP_LOG,
	SUBSTR( SUBSTR(STEP_DESCR, INSTR(STEP_DESCR, '***')+4), 1, INSTR(SUBSTR(STEP_DESCR, INSTR(STEP_DESCR, '***')+4), '***')-2 ) AS AFFECTED_ROWS
  VON UTL_JOB_STATUS
  WO datetime(LOG_D, 'unixepoch') >= date('now', 'start of month', '-3 month')
)
WÄHLEN SIE JB.SID,
  JB.MIN_LOG_DT ALS START_DT,
  strftime('%d.%m.%Y %H:%M', datetime(JB.MIN_LOG_DT, 'unixepoch')) ALS LOG_DT,
  JB.SOURCE,
  JB.LAYER,
  JB.JOB_NAME,
  FALLS
  WENN JB.ERROR_FLAG = 1 DANN 'FEHLER'
  WENN JB.ERROR_FLAG = 0 UND JB.END_FLAG = 0 UND strftime('%s','now') - JB.MIN_LOG_DT > 0,5*60*60 DANN 'BEHÄNGT' /* eine halbe Stunde */
  WENN JB.ERROR_FLAG = 0 UND JB.END_FLAG = 0 DANN 'LÄUFT'
  ANDERES 'OK'
  END ALS STATUS,
  ERR.STEP_LOG     ALS STEP_LOG,
  JB.CNT           ALS STEP_CNT,
  JB.AFFECTED_ROWS ALS AFFECTED_ROWS,
  strftime('%d.%m.%Y %H:%M', datetime(JB.MIN_LOG_DT, 'unixepoch')) ALS JOB_START_DT,
  strftime('%d.%m.%Y %H:%M', datetime(JB.MAX_LOG_DT, 'unixepoch')) ALS JOB_END_DT,
  JB.MAX_LOG_DT - JB.MIN_LOG_DT ALS JOB_DURATION_SEC
VON
  ( WÄHLEN SID, SOURCE, LAYER, JOB_NAME,
           MAX(UTL_JOB_STATUS_ID) ALS UTL_JOB_STATUS_ID,
           MAX(START_FLAG)       ALS START_FLAG,
           MAX(END_FLAG)         ALS END_FLAG,
           MAX(ERROR_FLAG)       ALS ERROR_FLAG,
           MIN(LOG_DT)           ALS MIN_LOG_DT,
           MAX(LOG_DT)           ALS MAX_LOG_DT,
           SUM(1)                ALS CNT,
           SUM(IFNULL(AFFECTED_ROWS, 0)) ALS AFFECTED_ROWS
    VON SRC
    GRUPPIEREN NACH SID, SOURCE, LAYER, JOB_NAME
  ) JB,
  ( WÄHLEN UTL_JOB_STATUS_ID, SID, JOB_NAME, STEP_LOG
    VON SRC
    WO 1 = 1
  ) ERR
WO 1 = 1
  UND JB.SID = ERR.SID
  UND JB.JOB_NAME = ERR.JOB_NAME
  UND JB.UTL_JOB_STATUS_ID = ERR.UTL_JOB_STATUS_ID
BESTELLEN NACH JB.MIN_LOG_DT DESC, JB.SID DESC, JB.SOURCE;

SQL Überprüfung der Möglichkeit zur Erhaltung einer neuen Sitzungsnummer

SELECT SUM (
  CASE WHEN start_job.JOB_NAME IS NOT NULL AND end_job.JOB_NAME IS NULL /* bereits ausgeführter Job abgeschlossen */
	    AND NOT ( 'y' = 'n' ) /* Parameter für Zwangsneustart */
       THEN 1 ELSE 0
  END ) AS IS_RUNNING
  FROM
    ( SELECT 1 AS dummy FROM UTL_JOB_STATUS WHERE sid = -1) d_job
  LEFT OUTER JOIN
    ( SELECT JOB_NAME, SID, 1 AS dummy
      FROM UTL_JOB_STATUS
      WHERE JOB_NAME = 'RPT_ACCESS_LOG' /* Jobname-Parameter */
	    AND STEP_NAME = 'ETL_START'
      GROUP BY JOB_NAME, SID
    ) start_job /* Beginn */
  ON d_job.dummy = start_job.dummy
  LEFT OUTER JOIN
    ( SELECT JOB_NAME, SID
      FROM UTL_JOB_STATUS
      WHERE JOB_NAME = 'RPT_ACCESS_LOG'  /* Jobname-Parameter */
	    AND STEP_NAME in ('ETL_END', 'ETL_ERROR') /* Stopstatus */
      GROUP BY JOB_NAME, SID
    ) end_job /* Ende */
  ON start_job.JOB_NAME = end_job.JOB_NAME
     AND start_job.SID = end_job.SID

Besonderheiten der Tabelle:

  • Der Beginn und das Ende des Datenverarbeitungsprozesses müssen durch die Schritte ETL_START und ETL_END begleitet werden.
  • Im Fehlerfall muss ein Schritt ETL_ERROR mit einer Beschreibung erstellt werden.
  • Die Menge der verarbeiteten Daten sollte hervorgehoben werden, beispielsweise durch Sterne.
  • Gleichzeitig kann die gleiche Prozedur mit dem Parameter force_restart=y gestartet werden; ohne diesen Parameter wird die Sitzungsnummer nur zur abgeschlossenen Prozedur ausgegeben.
  • Im regulären Modus kann die gleiche Datenverarbeitungsprozedur nicht parallel gestartet werden.

Die erforderlichen Operationen zur Bearbeitung der Tabelle sind die folgenden:

  • Abrufen der Sitzungsnummer des gestarteten ETL-Verfahrens
  • Einfügen eines Logeintrags in die Tabelle
  • Abrufen des letzten erfolgreichen Eintrags des ETL-Verfahrens

In Datenbanken wie Oracle oder Postgres können diese Operationen durch eingebaute Funktionen umgesetzt werden. Für SQLite ist ein externes Mechanismus notwendig, und in diesem Fall wurde es in PHP prototypisiert.

Fazit

Somit spielen Fehlermeldungen in Datenverarbeitungswerkzeugen eine entscheidende Rolle. Dennoch sind sie für eine schnelle Ursachenfindung oft nicht optimal. Wenn die Anzahl der Verfahren die Hundert erreicht, wird das Monitoring der Prozesse zu einem komplexen Projekt.

Der Artikel enthält ein Beispiel für eine mögliche Problemlösung in Form eines Prototyps. Der gesamte Prototyp eines kleinen Speichers ist auf GitLab verfügbar. SQLite PHP ETL-Dienstprogramme.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster