Eine der Herausforderungen beim Umgang mit einem neuen Datenbankdesign besteht darin, dass Sie Dinge wie die Größe der Tabellen am Ende nicht wissen, bis sie tatsächlich mit einer angemessenen Datenmenge gefüllt sind. Wenn das Design jedoch eventuelle Bedenken hinsichtlich der Skalierbarkeit berücksichtigen muss, können Sie es nicht bereitstellen, um diese Daten zu erhalten, bis die Schätzung abgeschlossen ist. Eine Möglichkeit, dies zu umgehen, besteht darin, Dinge aggressiv zu prototypisieren. Verwenden Sie zu diesem Zweck Staging-Hardware, auf der neue Anwendungen vorübergehend leben können, während Sie Details wie diese aussortieren. Sie können nur berücksichtigen, dass Sie die App verschieben und möglicherweise nach ein paar Monaten neu gestalten müssen, wenn Sie eine bessere Vorstellung davon haben, welche Daten darin angezeigt werden.
Die andere Möglichkeit, dieses Henne-Ei-Problem zu umgehen, besteht darin, einen Datengenerator zu schreiben. Erstellen Sie von Hand genügend Beispieldaten, um zu sehen, wie sie aussehen, wie dicht sie sind und wie ihre Werte verteilt sind. Schreiben Sie dann etwas, das diese Statistiken nimmt und einen größeren Datensatz erzeugt, der diesem ähnlich ist. Das wird man nie perfekt hinbekommen, muss es aber auch nicht. Das Generieren riesiger Datensätze, selbst mit einigen Fehlern, ist immer noch der beste verfügbare Weg, um die Datenbankgröße zu schätzen. Es gibt so viele Quellen für Overhead, dass es schwierig ist, dies zu berücksichtigen, dass alle gemessenen Tabellen- und Indexgrößen, die auf etwas wie Ihren Daten basieren, viel genauer sind als jeder andere Ansatz. Es gibt einen Grund, warum ich am Ende viele Fragen zu leistungsbezogenen Bedenken beantworte, indem ich zuerst pgbench verwende, um eine Datenbank der entsprechenden Größe zu erstellen.
Die Datengenerierung ist jedoch nicht einfach. Besonders das Generieren von realistischen Zeitstempeln ist immer lästig. Und egal, wie effizient Sie sie geschrieben haben, es dauert normalerweise länger als erwartet, bis sie ausgeführt werden – und noch länger, um die resultierenden Daten in eine Datenbank zu bringen und richtig zu indizieren.
Und das bleibt der Fall, egal wie oft Sie dies getan haben, denn selbst wenn Sie alles richtig machen, wird Murphys Gesetz eingreifen, um die Arbeit trotzdem schmerzhaft zu machen. Meine Computer zu Hause sind alle aus relativ billiger PC-Hardware gebaut. Nicht das billigste verfügbare Zeug – ich habe Standards – aber sicherlich nicht die gleiche Qualität, die ich den Leuten empfehlen würde, auf einem Server zu suchen. Das Datengenerierungsproblem dieser Woche erinnerte daran, warum bessere Hardware so viel wert ist, wie viel sie für geschäftskritische Aufgaben kostet.
Nachdem ich ein paar Milliarden Datenzeilen generiert und diesen Import 10 Stunden lang beobachtet hatte, war ich nicht erfreut, dass der ganze Job so abgebrochen wurde:
psql:load.sql:10: ERROR: invalid input syntax for type timestamp: "201^Q-04-14 12:17:55"
CONTEXT: COPY testdata, line 181782001, column some_timestamp: "201^Q-04-14 12:17:55"
Es stellte sich heraus, dass irgendwo während des Schreibens der 250 GB Testdaten, die ich generiert hatte, eine der ausgegebenen Zeilen beschädigt war. Zwei Bits wurden umgedreht, und die ausgeschriebenen Daten waren falsch. Ich weiß nicht genau, wo das passiert ist.
Die Erinnerung ist der wahrscheinlichste Verdächtige. Echte Server verwenden ECC-RAM, und das aus gutem Grund. Wenn Sie ein System mit viel RAM überwachen, kann die Anzahl der von ECC stillschweigend korrigierten Fehler schockierend sein. Das RAM, das ich zu Hause verwende, ist gut, aber die Fehlerraten auf jedem Speicher ohne Fehlererkennungs-/Korrekturfunktionen werden höher sein, als Sie vielleicht möchten – und werden nie erkannt, es sei denn, sie treten in Code auf, der zu einem Systemabsturz führt. Die Datengenerierung ist gut geeignet, um diese Probleme aufzudecken, da sie normalerweise mindestens eine CPU auf Ihrem Server möglicherweise mehrere Tage hintereinander stark belastet. Wenn Ihr System instabil ist, wird es verschlimmert, das System heiß zu machen und es für eine lange Zeit laufen zu lassen.
Eine zweite Schutzebene gegen diese Art von Korruption besteht darin, Prüfsummen auf Daten zu setzen, die auf die Festplatte geschrieben werden, um vor Fehlern beim Schreiben und erneuten Lesen der Daten zu schützen. Die vom ZFS-Dateisystem durchgeführte Block-Prüfsummenbildung ist eine der besseren Implementierungen davon. In meinem Fall hat es vielleicht keinen Unterschied gemacht, ob ich ZFS verwendet habe oder nicht. Wenn die Bits umgedreht worden wären, bevor die Blockprüfsumme passiert wäre, hätte ich Junk-Daten herausgeschrieben – mit einer passenden Junk-Prüfsumme – egal.
Mein nächster Schritt war, den Split zu verwenden Dienstprogramm, um meine riesige Datei zu nehmen und sie in weitere mundgerechte Stücke zu zerlegen – noch ein paar Stunden, um darauf zu warten, dass das fertig ist. Dann konnte ich damit beginnen, die guten Dateien zu laden, während ich die schlechten reparierte.
Angesichts der Tatsache, dass die resultierenden Dateien jeweils 13 GB groß waren und mein Server 16 GB RAM hat, konnte ich diesen Tippfehler mit einem Zeichen mit vi beheben. Theoretisch sollte das der Fall sein, aber ich habe langsam meine Zweifel, wenn ich bedenke, wie lange ich darauf gewartet habe, dass die Datei danach wieder zurückgeschrieben wird:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
21495 gsmith 20 0 8542m 8.3g 1544 R 98 53.0 419:56.70 vi datafile-ag
Das sind solide 7 Stunden, auf die ich nur darauf gewartet habe, dass dieser Tippfehler mit einem Zeichen behoben wird, damit ich das Laden der Testdaten beenden kann. Wie ich schon sagte, seriöse Datengenerierung ist nie einfach.