Eine Sportergebnis-Plattform, auf PostgreSQL migriert, ohne eine Zeile zu verlieren

Offizielle Wettkampfergebnisse werden Veranstaltung für Veranstaltung veröffentlicht. Familien und Trainer wollen aber eine ganze Karriere sehen. Diese Plattform sammelt jede Veranstaltung und baut daraus die Geschichte jeder Sportlerin, jedes Sportlers und jedes Vereins neu auf.

Das Problem

Die Quelle veröffentlicht Ergebnisse pro Veranstaltung, pro Tag und pro Region. Die Frage “Wie hat sich diese Athletin über drei Saisons entwickelt?” lässt sich dort nicht stellen. Die Plattform beantwortet sie: Sie fragt jede Veranstaltung regelmäßig ab, vereinheitlicht Namen und Vereine und indiziert alles nach Person.

Gestartet ist sie auf SQLite, und für eine erste Version war das die richtige Entscheidung. Als die Daten über eine Million Zeilen wuchsen und der Traffic in der Wettkampfsaison zunahm, wurden die Grenzen sichtbar: immer nur ein Schreibzugriff gleichzeitig, langsame Aggregat-Queries und keine saubere Möglichkeit, Ingest und Website auf getrennten Maschinen zu betreiben.

Was wir gemacht haben

Den Umzug als Migration mit Rückweg geplant. Wir haben die Datenschicht hinter einem schlanken Wrapper auf PostgreSQL portiert, beide Datenbanken parallel betrieben und die Query-Ergebnisse Seite für Seite verglichen, bevor wir umgeschaltet haben. Beim Cutover wurden alle 1.258.217 Zeilen kopiert und per Checksumme geprüft. Die alte Datenbank blieb zwei Wochen lang unangetastet als Rollback-Pfad, mit schriftlich festgehaltenen Schritten.

Behoben, was der Cutover ans Licht brachte. In den ersten Stunden tauchten zwei Betriebsfehler auf: ein Cron-Wrapper, der an einem Wert ohne Anführungszeichen scheiterte, und ein Backup-Tool, das eine Major-Version hinter dem Server lag. Beides war noch am selben Vormittag behoben, und das erste PostgreSQL-Backup wurde wiederhergestellt und geprüft, bevor irgendjemand die Migration für abgeschlossen erklärte.

Dort schnell gemacht, wo die Nutzer es merken. Die Vergleichsseite für Athleten brauchte 13 Sekunden, weil sie bei jedem Aufruf die gesamte Ergebnistabelle aggregierte. Nachdem die Query auf die Wettkämpfe des jeweiligen Athleten eingeschränkt war, lag sie bei 0,2 Sekunden, mit byte-identischer Ausgabe. Die Bestenlisten auf der Startseite wurden aus den Nutzeranfragen in einen Hintergrundjob verlagert. Ein Kaltstart der Seite sank damit von etwa 2,7 auf unter 0,2 Sekunden.

Was das zeigt

Ingest, Datenmodellierung, Datenbankmigration, Performance-Arbeit und Betrieb, alles von denselben Leuten. Die Datenseite wusste, welche Zahlen übereinstimmen mussten. Die Plattformseite wusste, wie man sie sicher bewegt.

Sagen Sie uns, was nicht funktioniert.

Ein paar Sätze reichen. Wir antworten innerhalb eines Werktags, und das erste Gespräch ist kostenlos.