2022-10-12

Modern Data Stack in a Box mit DuckDB

Guest post by Jacob Matson

Duck on a box

Dieser Beitrag ist eine Zusammenarbeit mit Jacob Matson und erscheint auch auf dataduel.co.

Zusammenfassung

Es gibt eine große Menge Literatur, z. B. 1 und 2, über das Skalieren von Datenpipelines. „Nutzt Kafka! Baut ein Lakehouse! Baut kein Lakehouse, nutzt Snowflake! Nutzt nicht Snowflake, nutzt XYZ!“ Mit Fortschritten bei Hardware und der raschen Reife von Datensoftware gibt es jedoch einen einfacheren Weg. Dieser Artikel zeigt den Weg zu hochperformanter Single-Node-Analytik mit einem quelloffenen MDS-in-a-box-Stack: Meltano, DuckDB, dbt und Apache Superset unter Windows mit Windows Subsystem for Linux (WSL). Es gibt viele Optionen innerhalb des MDS. Wenn Sie einen anderen Stack nutzen, um ein MDS-in-a-box zu bauen, teilen Sie ihn bitte mit der Community auf DuckDB Twitter, GitHub oder Discord oder im dbt Slack! Oder schauen Sie einfach vorbei für eine freundliche Debatte über unsere Werkzeugwahl!

Motivation

Was ist der Modern Data Stack, und warum ihn nutzen? Der MDS kann vieles bedeuten (siehe Beispiele und eine historische Einordnung), im Kern ist er aber die Rückkehr zu SQL für Datentransformationen durch die Kombination mehrerer Best-in-Class-Softwarewerkzeuge zu einem Stack. Ein typischer Stack umfasst (zumindest!) ein Werkzeug, das Daten aus Quellen extrahiert und in ein Data Warehouse lädt, dbt zum Transformieren und Analysieren dieser Daten im Warehouse und ein Business-Intelligence-Werkzeug. Der MDS nutzt die Zugänglichkeit von SQL zusammen mit Softwareentwicklungs-Best-Practices wie Git, damit Analysten ihre Wirkung in ihren Unternehmen skalieren können.

Warum einen gebündelten Modern Data Stack auf einer einzelnen Maschine bauen, statt auf mehreren Maschinen und einem Data Warehouse? Es gibt viele Vorteile!

Wenn Sie zu einer Open-Source-Community beitragen oder ein Produkt innerhalb des Modern Data Stack anbieten, gibt es einen zusätzlichen Nutzen!

Abwägungen

Eine Kernkomponente des MDS ist die unbegrenzte Skalierbarkeit von Compute. Wie passt das zum MDS-in-a-box-Ansatz? Heute können Cloud-Recheninstanzen deutlich stärker vertikal skalieren als früher (z. B. 224 Kerne und 24 TB RAM auf AWS!). Laptops sind leistungsfähiger denn je. Da neue OLAP-Werkzeuge wie DuckDB diese Rechenleistung besser nutzen können, ist horizontale Skalierung für viele Analysen nicht mehr nötig! Außerdem lässt sich dieses MDS-in-a-box leicht auf so viele Boxen verdoppeln, wie nötig, wenn nach Fachgebiet partitioniert wird. Unendliches Compute wird also geopfert, erheblicher Maßstab bleibt aber leicht erreichbar.

Durch diesen Kompromiss ist der Ansatz eher ein „Open Source Analytics Stack in a box“ als ein traditioneller MDS. Er opfert unendliche Skalierung für deutliche Vereinfachung und die anderen Vorteile oben.

Ein Problem wählen

Da die NBA-Saison bald beginnt, ist eine Monte-Carlo-artige Simulation der Saison sowohl aktuell als auch gut für analytisches SQL geeignet. Das ist ein besonders gutes Szenario, um die Grenzen von DuckDB zu testen, weil es nur einfache Eingaben braucht und leicht auf enorme Satzzahlen skaliert. Das gesamte Projekt liegt in einem GitHub-Repo, das Sie auf GitHub finden.

Die Umgebung aufbauen

Die detaillierten Schritte zum Aufbau des Projekts stehen im Repo, die groben Schritte wiederholen wir hier. Hinweis: Windows Subsystem for Linux (WSL) wurde gewählt, um Apache Superset zu unterstützen, die anderen Komponenten dieses Stacks können direkt auf jedem Betriebssystem laufen. Glücklicherweise ist Linux unter Windows sehr unkompliziert geworden.

  1. Ubuntu 20.04 unter WSL installieren.
  2. Pakete aktualisieren (sudo apt update).
  3. Python installieren.
  4. Das Git-Repo klonen.
  5. Im Terminal make build und dann make run ausführen.
  6. Super-Admin-Nutzer für Superset im Terminal anlegen, dann einloggen und die Datenbank konfigurieren.
  7. Testabfragen in Superset ausführen, um Ihre Arbeit zu prüfen.

Meltano als Wrapper für Pipeline-Plugins

In diesem Beispiel zieht Meltano mehrere Bits und Pieces zusammen, damit die Pipeline mit einem einzigen Statement laufen kann. Der erste Teil ist der Tap (Extractor) ‚tap-spreadsheets-anywhere‘. Dieser Tap erlaubt es, flache Datendateien aus verschiedenen Quellen zu holen. Hinweis: DuckDB kann direkt aus flachen Dateien konsumieren (lokal und über das Netz) oder aus SQLite- und PostgreSQL-Datenbanken. Dieser Tap wurde jedoch gewählt, um ein klares Beispiel dafür zu geben, statische Daten in Ihre Datenbank zu bringen, die sich leicht in der Datei meltano.yml konfigurieren lassen. Meltano wird außerdem nützlicher, je komplexer Ihre Datenquellen werden.

plugins:
extractors:
- name: tap-spreadsheets-anywhere
variant: ets
pip_url: git+https://github.com/ets/tap-spreadsheets-anywhere.git
# data sources are configured inside of this extractor

Als Nächstes der Target (Loader) ‚target-duckdb‘. Dieses Target kann Daten aus jedem Meltano-Tap entgegennehmen und in DuckDB laden. Ein Teil der Schönheit dieses Ansatzes: Sie müssen sich nicht mit der Extra-Komplexität einer typischen Datenbank herumschlagen. DuckDB kann eingelegt werden und ist ohne Konfiguration oder laufende Wartung einsatzbereit. Weil die Komponenten und die Daten am selben Ort liegen, ist Networking kein Thema und die Komplexität sinkt weiter.

loaders:
- name: target-duckdb
variant: jwills
pip_url: target-duckdb~=0.4
config:
filepath: /tmp/mdsbox.db
default_target_schema: main

Als Nächstes der Transformer: ‚dbt-duckdb‘. dbt ermöglicht Transformationen mit einer Kombination aus SQL und Jinja-Templating für zugängliches SQL-basiertes Analytics Engineering. Der dbt-Adapter für DuckDB unterstützt jetzt parallele Ausführung über Threads, was das MDS-in-a-box noch schneller macht. Da der Großteil der Arbeit in dbt passiert, wird dieser Teil später im Beitrag genauer beschrieben.

transformers:
- name: dbt-duckdb
variant: jwills
pip_url: dbt-core~=1.2.0 dbt-duckdb~=1.2.0
config:
path: /tmp/mdsbox.db

Zuletzt ist Apache Superset als Meltano-Utility enthalten, um Datenabfragen und Visualisierung zu ermöglichen. Superset nutzt DuckDBs SQLAlchemy-Treiber duckdb_engine, kann DuckDB also ebenfalls direkt abfragen.

utilities:
- name: superset
variant: apache
pip_url: apache-superset==1.5.0 markupsafe==2.0.1 duckdb-engine==0.6.4

Bei Superset muss die Engine so konfiguriert werden, dass DuckDB im „Read-only“-Modus geöffnet wird. Sonst kann nur eine Abfrage gleichzeitig laufen (gleichzeitige Abfragen verursachen Locks). Das verhindert auch das Aktualisieren des Superset-Dashboards, während die Pipeline läuft. In diesem Fall läuft die Pipeline in unter 8 Sekunden!

Die Daten aufbereiten

Der NBA-Spielplan wurde von basketball-reference.com heruntergeladen, und die Draft-Kings-Sieg-Totals vom 27. September wurden für die Sieg-Totals genutzt. Spielplan und Sieg-Totals bilden die gesamte für dieses Projekt nötige Eingabe. Nach der Umwandlung ins CSV-Format wurden sie ins GitHub-Projekt hochgeladen, und die Datei meltano.yml wurde aktualisiert, um auf die Dateipfade zu verweisen.

Sources laden

Sobald die Daten im Web auf GitHub liegen, kann Meltano eine Kopie nach DuckDB ziehen. Mit dem Befehl meltano run tap-spreadsheets-anywhere target-duckdb werden die Daten in DuckDB geladen und sind bereit für die Transformation in dbt.

dbt-Modelle bauen

Nachdem die Sources geladen sind, werden die Daten mit dbt transformiert. Zuerst werden die Source-Modelle sowie der Szenario-Generator angelegt. Dann werden die Zufallszahlen für diesen Simulationslauf erzeugt – die Zufallszahlen werden als Tabelle, nicht als View, festgehalten, damit nachfolgende erneute Läufe der Downstream-Modelle mit den Graph-Operatoren zum Debuggen möglich sind (z. B. dbt run -s random_num_gen+). Sobald die zugrunde liegenden Daten liegen, beginnt die Simulation, zuerst die Regular Season, dann die Play-in-Spiele und zuletzt die Playoffs. Da jede Spielrunde von der vorherigen abhängt, ist die Parallelisierung in diesem Modell begrenzt, was sich im dbt-DAG widerspiegelt, in diesem Fall bequem auf GitHub Pages gehostet.

Es gibt ein paar weitere Designentscheidungen, die sich lohnen zu erwähnen:

  1. Simulations- und Summary-Tabellen wurden in getrennte Modelle aufgeteilt, für leichtere Nutzung und Transparenz. Jede Simulationsrunde hat also ein Sim-Modell und ein End-Modell – so können die richtigen Parameter (Conference, Team, Elo-Rating) in jede folgende Runde übergeben werden.
  2. Um zu tiefe Abfragen zu vermeiden, wurden reg_season_end und playoff_sim_r1 als Tabellen materialisiert. Das ist beim Build etwas langsamer, die Leistungsgewinne beim Abfragen von Summary-Tabellen (z. B. season_summary) sind den Slowdown aber mehr als wert. Hinweis: Schon bei nur 10.000 Sims braucht die Datenbank etwa 150 MB auf der Platte. Bei 100.000 Simulationen wächst sie leicht auf ein paar GB.

Superset anbinden

Sobald die dbt-Modelle gebaut sind, kann die Datenvisualisierung beginnen. In Superset muss ein Admin-Nutzer angelegt werden, um sich einzuloggen. Die Anleitung zum Verbinden der Datenbank steht im GitHub-Projekt, ebenso ein Hinweis, wie man sie im „Read-only“-Modus verbindet.

Es gibt 2 Modelle für die Analyse, obwohl beliebig viele genutzt werden können. season_summary enthält verschiedene Summary-Statistiken für die Saison, und reg_season_sim enthält alle simulierten Spielergebnisse. Dieser zweite Datensatz erzeugt ein interessantes Histogramm. Um Datenvisualisierungen in Superset zu bauen, muss zuerst der Datensatz definiert, dann das Chart gebaut und zuletzt das Chart einem Dashboard zugewiesen werden.

Unten ein Beispiel-Superset-Dashboard mit mehreren Charts auf Basis dieser Daten. Superset kann die Daten klar zusammenfassen und das Ausmaß der Variabilität in der Monte-Carlo-Simulation zeigen. Die duckdb_engine-Abfragen lassen sich schnell aktualisieren, wenn neue Simulationen laufen.

mds_in_a_box_superset_1

mds_in_a_box_superset_2

Fazit

Das Ökosystem um DuckDB ist so gewachsen, dass es sich gut in den Modern Data Stack einfügt. Das MDS-in-a-box ist ein tragfähiger Ansatz für kleinere Datenprojekte und würde besonders gut für leselastige Analytik funktionieren. Es gab ein paar weitere Learnings aus diesem Experiment. Superset-Dashboards sind leicht zu bauen, aber sie sind nicht skriptbar und müssen in der GUI gebaut werden (die bezahlte gehostete Version, Preset, unterstützt den Export als YAML). Außerdem: Monte-Carlo-Analysen in SQL gehen, in einer anderen Sprache können sie aber leichter sein. Das zeigt jedoch, wie weit sich die Fähigkeiten von SQL dehnen lassen!

Nächste Schritte

Es gibt weitere Richtungen für dieses Projekt. Ein nächster Schritt könnte sein, diesen Workflow zu dockerisieren, für noch einfachere Deployments. Wenn Sie ein Docker-Beispiel zusammenstellen möchten, schreiben Sie uns! Eine andere Anpassung des Ansatzes könnte sein, die finalen Ausgaben in Parquet-Dateien zu landen und sie mit In-Memory-DuckDB-Verbindungen zu lesen. Diese Dateien könnten sogar in einem S3-kompatiblen Object Store landen (und trotzdem von DuckDB gelesen werden), das fügt gegenüber dem In-a-box-Ansatz jedoch Komplexität hinzu! Weitere MDS-Komponenten könnten auch für Data-Quality-Monitoring, Lineage-Tracking usw. integriert werden.

Josh Wills arbeitet außerdem an einer interessanten Erweiterung von dbt-duckdb! Mit der Bibliothek sqlglot könnte dbt-duckdb dbt-Modelle, die im SQL-Dialekt anderer Datenbanken (einschließlich Snowflake und BigQuery) geschrieben sind, automatisch nach DuckDB transpilieren. Stellen Sie sich vor, Sie könnten Ihre Abfragen lokal testen, bevor Sie sie in Produktion pushen… Kommen Sie in den DuckDB-Kanal des dbt Slack, um die Möglichkeiten zu diskutieren!

Schreiben Sie uns, wenn Sie diesen oder einen anderen Ansatz nutzen, um ein MDS-in-a-box zu bauen! Wenn Sie einen Gastbeitrag für den DuckDB-Blog schreiben möchten, melden Sie sich auf Discord!