
TL;DR
|
Bei Datenbankmigrationen zeigt sich das Problem mit den Scheindaten am deutlichsten. Eine Migration, die einen Index zu einer Tabelle mit 500 Zeilen in der Entwicklungsdatenbank hinzufügt, läuft in Millisekunden ab und besteht jeden Test. Dieselbe Migration an einer Produktions-Tabelle mit 8 Millionen Zeilen sperrt die Tabelle während Spitzenauslastung für 90 Sekunden. Niemand hat das kommen sehen, weil niemand es mit 8 Millionen Zeilen getestet hat.
Das ist kein Ausnahmefall. Es ist ein routinemäßiger Fehler, und er tritt auf, weil die für Tests verwendeten Daten nicht die Daten widerspiegeln, mit denen die Anwendung tatsächlich arbeitet.
Was dir Mock-Daten nicht verraten
Das Wichtigste zum Mitnehmen: Mock-Daten und Fixtures überprüfen, ob das Programm den erwarteten Fall bewältigt. Produktionsdaten überprüfen, ob das Programm den tatsächlichen Fall bewältigt. In der Lücke zwischen diesen beiden Dingen entstehen die meisten Produktionsvorfälle.
Fixtures und Factories sind nützlich. Sie bieten dir eine kontrollierte, wiederholbare Testumgebung. Mit ihnen kannst du Tests schreiben, die in Sekundenschnelle laufen, bestimmte Szenarien isolieren und konsistente Ergebnisse liefern. All das trifft nach wie vor zu.
Was sie dir jedoch nicht bieten können, ist die Komplexität, die sich im Laufe der Zeit in einer Produktionsdatenbank ansammelt.
Eine Drupal-Produktionsinstallation mit drei Jahren Inhalt enthält verwaisten Taxonomiebegriffe, Knoten mit fehlenden Felddaten aufgrund einer nicht vollständig abgeschlossenen Schemamigration, Inhaltstypen mit Anomalien bei der Zeichenkodierung aus einem Importlauf im Jahr 2021 sowie Benutzerkonten mit Berechtigungskombinationen, die unter einer älteren Rollenkonfiguration möglich waren, unter der aktuellen aber nicht mehr existieren sollten. Nichts davon ist in den Fixtures enthalten, denn die Fixtures wurden geschrieben, um darzustellen, wie die Daten aussehen sollten – nicht, wie sie nach Jahren des realen Einsatzes tatsächlich aussehen.
Eine Django-Produktionsanwendung mit aktiven Nutzern weist Abfragemuster auf, die eine Entwicklungsdatenbank nicht kennt. Bestimmte Filter, die bei 10.000 Datensätzen schnell sind, werden bei 2 Millionen zu vollständigen Tabellenscans. Bestimmte Verknüpfungen, die isoliert gut funktionieren, verhalten sich unter den Lastmustern, die der reale Einsatz erzeugt, anders. Eine N+1-Abfrage, die in der Entwicklung nicht auffällt, wird in der Produktivumgebung zu einem performance-Problem.
Das Problem mit den Scheindaten ist nicht, dass Entwickler schlechte Fixtures schreiben. Es liegt daran, dass Fixtures ein Modell der Realität sind – und Modelle sind immer unvollständig.
Kernaussage: Produktionsdatenbanken sind in dreierlei Hinsicht komplex, was Fixtures nicht nachbilden können: Volumen (die Datenmenge), Entropie (die angesammelten Inkonsistenzen aus der realen Nutzung) und Abfrageverhalten (wie sich die Datenbank-Engine unter realen Auslastungsmustern tatsächlich verhält). Alle drei Aspekte sind für das Testen von Bedeutung.
Das Volumen ist die offensichtlichste Dimension. Ein Feature, das 100 Datensätze verarbeitet, geht mit 10 Millionen Datensätzen anders um – und zwar in einer Weise, die von Indizierung, Abfrageplanung und Speicherzuweisung abhängt. Tests im Entwicklungsmaßstab decken diese Unterschiede nicht immer auf.
Entropie ist weniger sichtbar, aber ebenso wichtig. Echte Produktionsdatenbanken enthalten Daten, die nicht den aktuellen Schemaerwartungen entsprechen, da sich Schemata weiterentwickeln und Migrationen selten perfekt rückwirkend sind. Eine Drupal-Inhaltsmigration von vor fünf Jahren hat möglicherweise Felder in einem Zustand hinterlassen, mit dem der aktuelle Anwendungscode nicht rechnet, da der Code nach der Migration programmiert wurde und von sauberen Daten ausgeht. Tests anhand von Fixtures, die auf das aktuelle Schema abgestimmt sind, übersehen diese Fälle komplett.
Das Abfrageverhalten lässt sich am schwersten künstlich nachbilden. Datenbank-Engines treffen unterschiedliche Entscheidungen über Abfragepläne, abhängig von Tabellenstatistiken, Indexkardinalität und Datenverteilung. Eine Abfrage, die bei einem kleinen, einheitlichen Entwicklungsdatensatz effizient läuft, kann bei einem großen, heterogenen Datensatz in der Produktivumgebung einen anderen Ausführungsplan auslösen. Die einzige Möglichkeit, dies zuverlässig zu testen, besteht darin, mit Daten zu testen, die dieselben statistischen Eigenschaften wie die Produktivumgebung aufweisen.
Das Wichtigste auf einen Blick: Das Klonen von Daten auf Byte-Ebene erstellt in einer Preview-Umgebung eine produktionsäquivalente Kopie des Zustands der Produktionsdatenbank. In Kombination mit der Datensanierung erhalten Entwickler so eine Testumgebung mit der Komplexität der Produktionsumgebung, ohne dass echte Nutzerdaten offengelegt werden.
Upsun ist eine Platform-as-a-Service, die die Infrastrukturebene deines Anwendungsstacks verwaltet, sodass dein Team sich darum nicht kümmern muss. Wenn auf Upsun eine Vorschauumgebung aus einem Produktionszweig erstellt wird, enthält diese Umgebung einen Klon der Produktionsdatenbank auf Byte-Ebene zu diesem Zeitpunkt. Keine Schemakopie. Keine mit Fixtures gefüllte leere Datenbank. Eine originalgetreue Kopie der Daten, wie sie zum Zeitpunkt des Klonens in der Produktivumgebung vorliegen – bis hin zu denselben verwaisten Datensätzen, denselben Kodierungsanomalien und denselben Abfragestatistiken.
Der Klonvorgang findet auf der Speicherebene statt, was bedeutet, dass er unabhängig von der Datenbankgröße schnell abläuft. Eine 80-GB-Datenbank benötigt zum Klonen nicht 80 GB Zeit, da die Plattform den Vorgang als Dateisystemoperation und nicht als Datenübertragung behandelt.
Für die meisten Teams sieht der Prozess so aus:
# Create a new environment branched from production
upsun branch feature/new-search-index main
# The environment spins up with a full clone of production data
# Your feature code runs against real data from the first commit
Die Branch-Umgebung des Entwicklers enthält nun dieselben 8 Millionen Zeilen, auf die die Migration in der Produktivumgebung treffen wird. Das Hinzufügen eines Index, das die Produktionstabelle 90 Sekunden lang gesperrt hat, taucht in der Entwicklung auf – noch bevor es bereitgestellt wird –, sodass das Problem noch behoben werden kann.
Das Wichtigste auf einen Blick: Das Klonen von Produktionsdaten ist nur dann sinnvoll, wenn Entwickler sicher auf die geklonten Daten zugreifen und diese mit QA-Teams teilen können. Bei der Sanitisierung werden personenbezogene Daten entfernt oder maskiert, bevor der Klon eine Nicht-Produktionsumgebung erreicht, wodurch sowohl Datenschutzanforderungen als auch die praktischen Bedürfnisse regulierter Entwicklungsworkflows erfüllt werden.
Die offensichtliche Sorge beim Einbringen von Produktionsdaten in Entwicklungsumgebungen ist der Datenschutz. Produktionsdatenbanken enthalten echte Nutzerdaten: E-Mail-Adressen, Namen, Zahlungsreferenznummern, Gesundheitsakten – was auch immer die Anwendung speichert. Diese Daten sollten nicht für jeden Entwickler im Team zugänglich sein und sie sollten nicht in den URLs der Vorschauumgebung erscheinen, die an Kunden zur Überprüfung weitergegeben werden.
Die Datensanierung läuft als Teil des Verzweigungsprozesses ab, bevor die geklonten Daten die Vorschauumgebung erreichen. Ein Sanierungs-Hook ersetzt sensible Felder durch realistische, aber fiktive Werte: Echte E-Mail-Adressen werden durch generierte ersetzt, Namen werden ausgetauscht, Zahlungsdaten werden maskiert. Die Datenbank behält ihre strukturelle Komplexität und ihren Umfang bei, während die identifizierenden Informationen entfernt werden.
Bei einem Drupal-Projekt könnte ein Bereinigungs-Hook mit Drush etwa so aussehen:
hooks:
deploy: |
if [ "$PLATFORM_ENVIRONMENT_TYPE" != production ]; then
drush -y sql:sanitize --sanitize-email=user+%uid@example.com
fi
Der Hook läuft automatisch in jeder Nicht-Produktionsumgebung, was bedeutet, dass die Bereinigung strukturell und nicht prozedural erfolgt. Es ist nicht darauf angewiesen, dass jemand daran denkt, ihn auszuführen; er läuft, weil die Konfiguration dies vorsieht.
Das Ergebnis ist eine Vorschauumgebung mit Daten in der Produktivumgebung, Abfragemustern in Produktionskomplexität und ohne echte Benutzerinformationen. Die Qualitätssicherung (QA) kann damit testen. Entwickler können damit Fehler beheben. Prüfer können sicherstellen, dass die Umgebung die Bedingungen der Produktivumgebung widerspiegelt. Keiner von ihnen sieht echte Benutzerdaten.
Das Wichtigste auf einen Blick: Wenn die QA ein Feature freigibt, das anhand echter Produktionsdaten getestet wurde, hat diese Freigabe eine andere Bedeutung als bei Tests anhand von Fixtures. Die Kluft zwischen „von der QA freigegeben“ und „verhält sich wie in der Produktivumgebung“ wird deutlich kleiner.
Die praktische Veränderung liegt darin, was Testergebnisse bedeuten.
Wenn eine Funktion die Qualitätssicherung in einer mit Fixtures bestückten Umgebung besteht, lautet das Ergebnis: Diese Funktion funktioniert korrekt mit idealisierten Daten in einer kontrollierten Umgebung. Das ist nützlich, lässt aber eine Kategorie von Fehlern offen, die nur Produktionsdaten aufdecken würden.
Wenn eine Funktion die Qualitätssicherung in einer aus der Produktivumgebung geklontem Umgebung besteht, lautet das Ergebnis: Diese Funktion funktioniert korrekt mit den tatsächlichen Daten, mit denen sie in der Produktivumgebung zu tun haben wird – einschließlich der Randfälle, des Datenvolumens und der kumulierten Entropie aus der realen Nutzung. Das ist ein deutlich aussagekräftigeres Signal.
Bei regulierten Anwendungen, bei denen die Freigabe durch die Qualitätssicherung Teil eines Compliance-Prozesses ist, spielt diese Unterscheidung für Auditoren eine Rolle. Der Nachweis, dass Tests mit produktionsäquivalenten Daten durchgeführt wurden, ist aussagekräftiger als Tests mit Testdaten, da er zeigt, dass die Testbedingungen die Realität widerspiegelten.
Für Teams, die bereits Produktionsvorfälle erlebt haben, die auf Daten zurückzuführen waren, die die Test-Fixtures nicht abdeckten, beseitigt dies eine Unsicherheit, die derzeit zwischen der Bereitstellung und der Zuversicht steht.
Behalte sie. Fixtures sind das richtige Werkzeug für Unit-Tests, isolierte Szenarien und schnelle Feedback-Schleifen. Das Klonen von Produktionsdaten ergänzt sie, ersetzt sie aber nicht: Fixtures dienen dazu, zu testen, wie sich dein Code verhalten sollte, Produktionsdaten dazu, zu testen, wie er sich tatsächlich im großen Maßstab verhält. Die beiden Ansätze beantworten unterschiedliche Fragen, und ein ausgereiftes Test-Setup nutzt beide.
Ist das Klonen von Produktionsdaten aus Sicht der DSGVO oder HIPAA sicher?
Der Klon selbst ist eine Kopie der Daten der Produktivumgebung und unterliegt denselben Verpflichtungen wie die Produktivumgebung, bis er bereinigt wurde. Der Bereinigungs-Hook läuft als Teil des Prozesses zur Erstellung der Umgebung ab und sollte als obligatorischer Schritt für jede regulierte Anwendung betrachtet werden. Nach der Bereinigung enthält die Umgebung keine echten personenbezogenen Daten mehr und kann von Entwicklern und der Qualitätssicherung ohne zusätzliche Verpflichtungen zum Umgang mit Daten genutzt werden.
Wie aktuell sind die geklonteten Daten?
Der Klon spiegelt den Stand der Produktionsdaten zum Zeitpunkt der Erstellung des Branches wider. Es handelt sich um einen Snapshot, nicht um eine Live-Synchronisierung. Für die meisten Entwicklungs- und QA-Zwecke ist dies ausreichend, da das Ziel eine der Produktion entsprechende Komplexität und nicht Echtzeitdaten ist. Für Tests, die speziell aktuelle Daten erfordern, können Branches anhand des neuesten Produktions-Snapshots neu erstellt werden.
Verlangsamt das Klonen einer großen Produktionsdatenbank die Erstellung der Umgebung?
Nicht nennenswert. Das Klonen erfolgt auf der Speicherebene als Dateisystemoperation, was bedeutet, dass die dafür benötigte Zeit weitgehend unabhängig von der Datenbankgröße ist. Eine Umgebung, die von einer Produktionsdatenbank mit 80 GB Daten abzweigt, benötigt etwa genauso lange zum Erstellen wie eine mit 1 GB.
Was ist, wenn unsere Produktionsdatenbank Daten enthält, die wir nicht in eine Nicht-Produktionsumgebung übertragen dürfen – auch nicht in bereinigter Form?
Der Anonymisierungs-Hook lässt sich so konfigurieren, dass bestimmte Tabellen komplett ausgeschlossen werden, anstatt sie zu maskieren. Bei Daten, die unter keinen Umständen die Produktivumgebung verlassen dürfen, werden diese Tabellen standardmäßig vom Klon ausgeschlossen und stattdessen mit synthetischen Daten gefüllt. Der Rest der Datenbank behält seine Produktionskomplexität bei.
Können wir den Sanitisierungs-Hook auf bestimmte Datentypen anwenden, statt auf die gesamte Datenbank?
Ja. Sanitisierungs-Hooks haben vollen Zugriff auf die Datenbank und können unterschiedliche Maßnahmen auf verschiedene Tabellen anwenden: E-Mail-Adressen in einer Tabelle maskieren, Namen in einer anderen ersetzen und nicht sensible Tabellen unberührt lassen. Die Konfiguration ist so detailliert, wie es die Anwendung erfordert.