Ebook · Hoofdstuk 9 van 10

Monitoring en Onderhoud

Een datawarehouse dat niemand bewaakt is een datawarehouse dat morgen kapot is. Operations als discipline.

Observability voor data

18 min leestijd Gevorderd

Software-engineering heeft observability volwassen gemaakt: logs, metrics, traces. Data engineering loopt achter, maar haalt in. Een modern monitoring-stack voor een DWH dekt vier pijlers: freshness, volume, schema en distributie. Plus klassieke pipeline-orchestratie monitoring.

Disaster recovery: RPO en RTO voor data

Hoe lang mag je DWH stilliggen voordat het pijn doet? En hoeveel data mag je verliezen? Twee getallen die je expliciet moet hebben:

Cloud-warehouses bieden hier ingebouwde antwoorden. Snowflake's time travel (tot 90 dagen) en fail-safe (7 extra dagen) ondervangen de meeste data-corruptie scenario's. BigQuery heeft 7 dagen time travel. Microsoft Fabric en Delta Lake gebruiken Delta time travel. Dit alles dekt vooral logische rampen (verkeerde DELETE, foute deploy); voor regio-uitval heb je cross-region replicatie nodig — beschikbaar maar duur, alleen activeren als je RTO/RPO het vragen.

De vier pijlers van data observability

Pillar 1: freshness monitoring

Het meest voorkomende incident is "data is oud" — een failed pipeline die niemand opmerkte. dbt heeft hier ingebouwde support:

# sources.yml
sources:
  - name: app
    schema: raw_app
    tables:
      - name: orders
        loaded_at_field: updated_at
        freshness:
          warn_after:  {count: 6,  period: hour}
          error_after: {count: 12, period: hour}
      - name: customers
        loaded_at_field: updated_at
        freshness:
          warn_after:  {count: 24, period: hour}
          error_after: {count: 48, period: hour}
-- Run als onderdeel van CI/CD of orkestrator
-- $ dbt source freshness
-- Faalt als data te oud is, met een nette samenvatting

Voor non-dbt projecten een eenvoudig SQL-statement:

-- Geeft > 0 als de data te oud is
SELECT
    'orders' AS table_name,
    MAX(updated_at) AS last_loaded,
    DATEDIFF('hour', MAX(updated_at), CURRENT_TIMESTAMP) AS hours_old
FROM   raw_app.orders
HAVING hours_old > 6;

Pillar 2: volume monitoring

Verwacht aantal nieuwe rijen per dag verschilt per tabel — maar drift uit een baseline is altijd verdacht.

-- Vergelijking met 7-daags rolling gemiddelde
WITH daily_loads AS (
  SELECT DATE_TRUNC('day', load_ts) AS load_date,
         COUNT(*) AS rows_loaded
  FROM   stg_orders
  GROUP  BY 1
),
baseline AS (
  SELECT load_date, rows_loaded,
         AVG(rows_loaded) OVER (
           ORDER BY load_date
           ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING
         ) AS avg_7d
  FROM   daily_loads
)
SELECT *
FROM   baseline
WHERE  load_date = CURRENT_DATE - 1
  AND  ABS(rows_loaded - avg_7d) / NULLIF(avg_7d, 0) > 0.5;   -- > 50% drift

Pillar 3: schema drift

Een producer zet stilletjes order_total om naar order_total_eur en je dashboard wijst nullen. Schema-drift detectie kan zo simpel als een snapshot zijn:

-- Bewaar dagelijks de huidige schema's
INSERT INTO meta.schema_snapshots
SELECT CURRENT_DATE,
       table_schema,
       table_name,
       LISTAGG(column_name || ':' || data_type, ',') WITHIN GROUP (ORDER BY ordinal_position)
FROM   information_schema.columns
WHERE  table_schema NOT IN ('INFORMATION_SCHEMA','PG_CATALOG')
GROUP  BY 1, 2, 3;

-- Detecteer veranderingen ten opzichte van gisteren
SELECT today.table_schema, today.table_name,
       today.cols  AS today_cols,
       yest.cols   AS yest_cols
FROM   meta.schema_snapshots today
JOIN   meta.schema_snapshots yest
  ON   today.table_schema = yest.table_schema
 AND   today.table_name   = yest.table_name
 AND   yest.snapshot_date = today.snapshot_date - 1
WHERE  today.cols <> yest.cols;

Pillar 4: distribution drift

Stel: 95% van je orders heeft normaal status='completed'. Vandaag is het 60%. Je dataset is technisch in orde, maar er zit een upstream probleem.

SELECT
    order_status,
    COUNT(*) * 1.0 / SUM(COUNT(*)) OVER () AS pct_today,
    LAG(COUNT(*) * 1.0 / SUM(COUNT(*)) OVER ()) OVER (ORDER BY snapshot_date) AS pct_yesterday
FROM   fact_orders
WHERE  load_date IN (CURRENT_DATE, CURRENT_DATE - 1)
GROUP  BY snapshot_date, order_status;

Tools die dit automatiseren met ML-baselining: Monte Carlo, Bigeye, Soda, Anomalo. Voor lichtere setups: Elementary (open source dbt-package).

Pipeline / orchestrator monitoring

Buiten data zelf moeten ook je pipelines bewaakt worden:

Airflow biedt een eenvoudige Slack-callback bij fouten:

from airflow.operators.python import PythonOperator
from urllib import request
import json, os

def slack_on_failure(context):
    payload = {
      "text": f":x: *{context['task_instance'].dag_id}* — task `{context['task_instance'].task_id}` failed.\n"
              f"Run: {context['run_id']}\n"
              f"Log: {context['task_instance'].log_url}"
    }
    req = request.Request(
        os.environ["SLACK_WEBHOOK"],
        data=json.dumps(payload).encode(),
        headers={"Content-Type": "application/json"})
    request.urlopen(req)

# DAG default args
default_args = {
    "on_failure_callback": slack_on_failure,
    "retries": 2,
    "retry_delay": timedelta(minutes=5),
}

SLI's, SLO's en SLA's voor data

Net als webservices kunnen data-producten doelen krijgen:

Voor een datawarehouse zijn typische SLI's:

Alert design — niet schreeuwen

De grootste valkuil is alert fatigue: te veel meldingen, niemand kijkt nog. Regels:

Test je alerts

Een alert die nog nooit gevuurd heeft, weet je niet of hij werkt. Disable af en toe een pipeline op de staging environment om te zien of de juiste mensen ge-paged worden. Geen surprise op zaterdagochtend.

Onderhoud: de stille killer

Een DWH dat niet onderhouden wordt rot weg. Plan periodiek:

On-call rotatie en runbooks

Wanneer een DWH bedrijfskritisch wordt, hoort er een on-call rotatie bij. Twee elementen die het verschil maken tussen rustige en woelige weken:

Capacity planning en groei-monitoring

Een DWH groeit. Wat vandaag past in een Medium-warehouse vraagt over een jaar een Large. Monitor minimaal:

Postmortems

Na elk significant incident: een blame-free postmortem met:

  1. Tijdlijn (wanneer ontdekt, wanneer hersteld, hoe lang impact?)
  2. Root cause analysis (de "5 whys")
  3. Wat ging goed — herhaalbare reflexen
  4. Wat ging slecht — verbeterpunten
  5. Concrete actiepunten met eigenaar en deadline

Niet om te wijzen, maar om te leren. Een postmortem die voor de derde keer dezelfde root cause noteert verdient een actie op systeemniveau, niet weer een training.

Documentatie als onderhoud

Documentatie hoort bij onderhoud, niet bij features. Tools die het meegroeien afdwingen: dbt docs (auto-generated), DataHub, Atlan. Minimaal vereist per tabel:

Key takeaways

  • Vier pijlers: freshness, volume, schema, distributie. Dek ze allemaal.
  • Alert op user-impact (data oud, dashboard kapot), niet op interne oorzaak.
  • SLI's en SLO's geven data-producten dezelfde discipline als web-producten.
  • Pipeline-monitoring zit naast data-monitoring — beide nodig.
  • Postmortems zijn blame-free en eindigen met actiepunten met eigenaar.
  • Documentatie en cleanup zijn onderdeel van onderhoud, niet "later".
  • Capacity planning vóór de pijngrens, niet erna.

Veelgestelde vragen

Wat zijn de vier pijlers van data observability?

Freshness (recent genoeg?), volume (juiste aantal rijen?), schema (kolommen ongewijzigd?) en distributie (verandert NULL-percentage of categorieverdeling?). Plus klassieke pipeline-orchestratie monitoring.

Hoe monitor je data freshness?

dbt source freshness checks via loaded_at_field met warn_after en error_after thresholds. Voor non-dbt projecten: MAX(updated_at) tegen CURRENT_TIMESTAMP. Tools als Monte Carlo, Bigeye en Soda automatiseren met ML-baselines.

Wat is het verschil tussen SLI, SLO en SLA?

SLI is een meetbaar getal (% queries onder 5 sec), SLO is je interne doelstelling (99%), SLA is een formele afspraak met afnemers met consequenties. Voor data: freshness, completeness, query latency, dashboard beschikbaarheid.

Hoe voorkom je alert fatigue?

Alert op symptoom, niet op oorzaak. Severity-tiers: INFO/WARN/CRIT. Routeer naar specifieke teams. Test alerts periodiek. Een alert die nooit gevuurd heeft is onbekend kwantiteit.

Wat hoort bij periodiek onderhoud?

Storage cleanup, statistics refresh, VACUUM op Redshift, re-clustering monitoring, permission audits, documentation review. Op lakehouses ook compaction en vacuum/expire snapshots op Delta- of Iceberg-tabellen.

Wat is een postmortem?

Blame-free analyse na incident: tijdlijn, root cause (5 whys), wat ging goed, wat ging slecht, actiepunten met eigenaar. Doel: leren, niet wijzen. Terugkerende root cause vraagt systeemverbetering.