StatusTypeRelevance

Status

Was brauchen wir, um Energie-UseCases ins System zu bringen?
ClickHouse? Superset? Und wie bleibt das Ganze trotzdem handhabbar?


Dieses Dokument beschreibt die technische Umsetzung der ClickHouse-Integration.

Es betrachtet zwei voneinander getrennte Betriebsabläufe:

  1. Schema- / Migration-Sicht
    Tabellen werden aus Git-Modellen generiert, DDL wird ausgerollt und versioniert.

  2. Ingestion-Sicht
    Parquet-Daten aus dem Data Lake werden in die entsprechenden ClickHouse-Tabellen geladen und validiert.

Diese beiden Abläufe sind bewusst getrennt. Änderungen an Tabellenstrukturen und das Laden von Daten folgen unterschiedlichen Lebenszyklen.


🧠 Schema- & Migration-Sicht

„Wie kommen Tabellen von YAML ins echte ClickHouse? Und wer drückt auf welchen Knopf?“

Es gibt ein zentrales Git-Repository, in dem Tabellen beschrieben sind.

Für jede modellierte Tabelle existiert ein eigenes Verzeichnis mit:

  • model.yaml - deklarative Beschreibung der Tabellenstruktur
  • template.sql.j2 - SQL-Template für die Generierung

Beispielhafte Struktur im Repository:

data-models/
  tables/
    fact_reservationdata_device/
      model.yaml
      template.sql.j2
    fact_observability_timeseries/
      model.yaml
      template.sql.j2

  migrations/
    V001__initial_setup.sql
    V002__add_index.sql

Das Git-Repository ist die führende Quelle für das Schema modellierter Tabellen.
ClickHouse selbst wird nicht als Schema-Editor verwendet.


🔧 Schritt 1 - Entwickler erstellt oder ändert ein Modell

Neue Tabellen oder Schemaänderungen werden durch Änderungen an model.yaml beschrieben.

Typischer Ablauf:

  1. Entwickler passt model.yaml an
  2. Pull Request
  3. Review
  4. Merge

Damit bleiben alle Änderungen nachvollziehbar und versioniert.


🚀 Schritt 2 - Flux synchronisiert Änderungen ins Cluster

Flux erkennt Änderungen im Repository und synchronisiert die relevanten Artefakte ins Cluster.

Dabei werden unter anderem bereitgestellt:

  • model.yaml
  • template.sql.j2
  • bestehende Migrationen

Diese Dateien werden typischerweise als ConfigMaps im Cluster verfügbar gemacht.

Flux sorgt außerdem dafür, dass das entsprechende Argo WorkflowTemplate für Schema-Apply verfügbar ist.


🏭 Schritt 3 - Argo startet den Schema-Apply-Workflow

Für jeden Tenant existiert eine eigene Datenbank:

tenant_<name>

Der Workflow wird entweder durch Flux oder durch einen periodischen CronJob ausgelöst.

Der Workflow besteht typischerweise aus zwei Containern.


Container A - model2ddl (Renderer)

Dieser Container erzeugt aus dem Modell die tatsächliche SQL-Definition.

Inputs:

  • model.yaml
  • template.sql.j2
  • Parameter wie z. B. db=tenant_test

Der Renderer erzeugt daraus konkrete SQL-Dateien.

Beispiel:

/out/001_fact_reservationdata_device.sql

Diese Dateien liegen in einem temporären Volume (emptyDir).

Wichtig:

Der Renderer erzeugt nur SQL.

  • Es werden keine Änderungen zurück ins Git geschrieben.
  • Das Cluster ist Ausführungsumgebung, nicht Quelle des Modells.

Container B - migration-runner

Dieser Container führt die erzeugten SQL-Migrationen aus.

Ablauf:

  1. Er liest die generierten SQL-Dateien.
  2. Er prüft in ClickHouse, welche Migrationen bereits angewendet wurden.
  3. Neue Migrationen werden ausgeführt.
  4. Die Migration wird in einer Tracking-Tabelle registriert.

Beispiel:

INSERT INTO schema_migrations VALUES ('tenant_test', '001_fact_reservationdata_device');

Ergebnis:

  • Die Tabelle existiert jetzt in tenant_test.
  • Superset kann darauf zugreifen.
  • Loader-Jobs können Daten einfügen.

📦 Ingestion-Sicht

„Wie kommen Parquet-Dateien aus dem Data Lake in die Tabellen?“

Die Ingestion-Pipeline ist unabhängig von der Schema-Pipeline.

Das verhindert, dass ein Schema-Change laufende Datenimporte stört.


⏳ Schritt 1 - Parquet erscheint im Data Lake

Ein bestehender Workflow erzeugt Parquet-Dateien, z. B. unter:

/curated/reservationdata/device/2025-11/

Der Data Lake bleibt die Source of Truth.

ClickHouse dient als optimiertes Query-Backend.


🚨 Schritt 2 - Ingestion-Workflow startet

Der Workflow kann gestartet werden durch:

  • Zeitplan
  • Storage-Event
  • manuellen Trigger

Der Workflow besteht typischerweise aus drei Schritten.


🧱 Step A - ClickHouse Loader

Ein Container führt SQL-Statements gegen ClickHouse aus.

Typischerweise über clickhouse-client.

Beispiel:

INSERT INTO tenant_test.fact_reservationdata_device
SELECT *
FROM url('https://blob/.../*.parquet?sv=...', 'Parquet');

Ergebnis:

Neue Parquet-Dateien werden in die entsprechende Tabelle geladen.


🔍 Step B - Validierung

Nach dem Import werden einfache Plausibilitätschecks ausgeführt.

Typische Prüfungen:

1. Zeilenanzahl prüfen

SELECT count() FROM ...;

2. Stichprobe vergleichen

SELECT cityHash64(*) FROM ... LIMIT 100;

Wenn die Ergebnisse nicht erwartungsgemäß sind:

  • Workflow schlägt fehl
  • Monitoring / Alerting greift

📣 Step C - Notification

Optional kann der Workflow zusätzliche Aktionen auslösen:

  • Slack-Benachrichtigung
  • Monitoring-Event
  • Aktualisierung eines Dashboards

🧩 Zusammenspiel der beiden Schienen

Die beiden Betriebsabläufe laufen unabhängig voneinander.

Schema-Pipeline

läuft nur, wenn sich Modelle ändern.

Ingestion-Pipeline

läuft regelmäßig oder ereignisbasiert.

Das hat mehrere Vorteile:

  • Schemaänderungen blockieren keine Datenimporte
  • Ingestion-Fehler beeinflussen nicht das Schema
  • klare Verantwortlichkeiten

📝 Zusammenfassung

Schema-Pipeline

  1. Entwickler ändert model.yaml
  2. Pull Request wird gemerged
  3. Flux synchronisiert Artefakte ins Cluster
  4. Argo startet schema-apply
  5. model2ddl erzeugt SQL
  6. migration-runner führt Migrationen aus

Ingestion-Pipeline

  1. Parquet erscheint im Data Lake
  2. Argo startet Ingestion-Workflow
  3. Loader importiert Daten nach ClickHouse
  4. Validator prüft Datenintegrität
  5. Optional: Notification

Das Modell bleibt stabil und nachvollziehbar, während Datenimporte unabhängig davon skaliert werden können. Auch bei vielen Tenants bleibt der Ablauf konsistent und reproduzierbar.