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:
-
Schema- / Migration-Sicht
Tabellen werden aus Git-Modellen generiert, DDL wird ausgerollt und versioniert. -
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 Tabellenstrukturtemplate.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:
- Entwickler passt
model.yamlan - Pull Request
- Review
- 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.yamltemplate.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.yamltemplate.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:
- Er liest die generierten SQL-Dateien.
- Er prüft in ClickHouse, welche Migrationen bereits angewendet wurden.
- Neue Migrationen werden ausgeführt.
- 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
- Entwickler ändert
model.yaml - Pull Request wird gemerged
- Flux synchronisiert Artefakte ins Cluster
- Argo startet
schema-apply model2ddlerzeugt SQLmigration-runnerführt Migrationen aus
Ingestion-Pipeline
- Parquet erscheint im Data Lake
- Argo startet Ingestion-Workflow
- Loader importiert Daten nach ClickHouse
- Validator prüft Datenintegrität
- 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.