Veröffentlicht in

PostgreSQL nach dem Distributions-Upgrade: „Version von Sortierfolge stimmt nicht überein“

Nach einem Distributions-Upgrade – in meinem Fall Debian Bookworm auf Trixie, auf dem die Mastodon-Instanz läuft – begrüßt mich nach Mastodon nun auch PostgreSQL plötzlich bei jeder Verbindung mit dieser Warnung:

WARNUNG: Version von Sortierfolge für Datenbank "mastodon_production" stimmt nicht überein
DETAIL: Die Datenbank wurde mit Sortierfolgenversion 2.36 erzeugt,
        aber das Betriebssystem hat Version 2.41.
HINT: Bauen Sie alle Objekte in dieser Datenbank, die die Standardsortierfolge
      verwenden, neu und führen Sie
      ALTER DATABASE mastodon_production REFRESH COLLATION VERSION aus [...]

Die Datenbank läuft weiter, nichts ist kaputt – zumindest noch nicht. Aber die Warnung einfach zu ignorieren oder nur wegzudrücken wäre ein Fehler. Warum, dazu gleich mehr.

Was ist da eigentlich passiert?

PostgreSQL sortiert Text nicht selbst. Wenn eine Datenbank mit einer Locale wie de_DE.UTF-8 angelegt wurde, delegiert PostgreSQL die Frage „kommt Müller vor oder nach Muller?“ an die C-Bibliothek des Betriebssystems – die glibc. Deren Sortierregeln (Collations) sind aber nicht in Stein gemeißelt: Mit neuen glibc-Versionen ändern sich gelegentlich Details, etwa bei Umlauten, Sonderzeichen oder Zeichen aus anderen Schriftsystemen.

Genau das passiert bei einem großen Distributions-Upgrade. Bookworm liefert glibc 2.36, Trixie glibc 2.41 – und PostgreSQL merkt sich, mit welcher Collation-Version eine Datenbank erzeugt wurde. Stimmt die gespeicherte Version nicht mehr mit der des Systems überein, kommt die Warnung.

Das ist übrigens kein Debian-Spezifikum. Dasselbe passiert auf Ubuntu, RHEL, Fedora, Arch oder jeder anderen Distribution, sobald ein Upgrade eine neue glibc-Version mitbringt. Auch beim Umzug einer Datenbank auf einen anderen Host mit abweichender glibc taucht die Meldung auf. Wer statt glibc-Locales ICU-Collations nutzt, hat das gleiche Spiel bei ICU-Versionssprüngen.

Warum die Warnung ernst zu nehmen ist

B-Tree-Indizes auf Textspalten sind physisch in Sortierreihenfolge abgelegt – und zwar in der Reihenfolge, die zum Zeitpunkt des Indexaufbaus galt. Ändert die neue glibc die Sortierregeln auch nur minimal, passt der Index nicht mehr zu dem, was PostgreSQL jetzt für „sortiert“ hält. Der Index ist dann aus Sicht der Datenbank korrupt, ohne dass es jemand merkt.

Die möglichen Folgen sind unangenehm, weil sie leise auftreten:

  • Abfragen über den Index finden vorhandene Zeilen nicht mehr – Daten scheinen zu „fehlen“, obwohl sie da sind.
  • Unique-Indizes greifen nicht mehr zuverlässig – Duplikate rutschen durch, etwa doppelte Benutzernamen oder E-Mail-Adressen.

Und hier liegt die eigentliche Falle: Der im HINT genannte Befehl ALTER DATABASE ... REFRESH COLLATION VERSION aktualisiert nur die gespeicherte Versionsnummer. Er repariert keinen einzigen Index. Wer nur den Refresh ausführt, schaltet die Warnleuchte aus, während das Problem bestehen bleibt. Die Reihenfolge muss lauten: erst reindizieren, dann refreshen.

Die Lösung in vier Schritten

Da REINDEX exklusive Sperren auf die jeweiligen Tabellen nimmt, gehört die Aktion in ein Wartungsfenster. Bei einer Mastodon-Instanz heißt das: Dienste kurz stoppen.

1. Anwendung stoppen – damit während des Reindex nichts schreibt:

systemctl stop mastodon-web mastodon-sidekiq mastodon-streaming

2. Datenbank reindizieren – am bequemsten mit dem CLI-Tool:

sudo -u postgres reindexdb mastodon_production

Bei mehreren Datenbanken auf dem Cluster erledigt reindexdb --all gleich alles auf einmal. Je nach Datenbankgröße dauert das eine Weile; außerdem braucht es temporär Plattenplatz in der Größenordnung des jeweils größten Index.

3. Collation-Version aktualisieren – und zwar nicht nur für die eigentliche Datenbank, sondern auch für die System-Datenbanken, sonst meldet sich die Warnung dort weiter:

sudo -u postgres psql -c "ALTER DATABASE mastodon_production REFRESH COLLATION VERSION;"
sudo -u postgres psql -c "ALTER DATABASE template1 REFRESH COLLATION VERSION;"
sudo -u postgres psql -c "ALTER DATABASE postgres REFRESH COLLATION VERSION;"

4. Dienste wieder starten:

systemctl start mastodon-web mastodon-sidekiq mastodon-streaming

Fertig. Die Warnung ist weg – und diesmal zu Recht.

Vorher: Backup. Aber welches?

Für diese Aktion reicht ein Dump der betroffenen Datenbank; am Dateisystem, an Uploads oder Konfigurationen ändert sich nichts:

sudo -u postgres pg_dump -Fc mastodon_production > mastodon_production_$(date +%F).dump

Kleine Randnotiz: Auch pg_dump zeigt beim Verbinden die Collation-Warnung an – das ist harmlos. Die Meldung landet auf stderr, nicht in der Dump-Datei. Der Dump selbst ist eine logische Beschreibung der Daten; Indizes werden beim Restore ohnehin komplett neu und mit der dann aktiven glibc-Version aufgebaut. Ein Dump/Restore ist deshalb sogar einer der sauberen Wege, das Collation-Problem loszuwerden.

Wer die Datenbank in einer VM auf einem Hypervisor betreibt, bei dem Snapshots zwei Klicks kosten (Proxmox, libvirt & Co.), nimmt zusätzlich einen Snapshot mit – nicht wegen des Reindex, sondern als bequemer „Alles auf Anfang“-Knopf, falls nach dem Distributions-Upgrade noch andere Überraschungen lauern. Danach den Snapshot wieder löschen, damit er nicht ewig mitwächst.

Wer ist überhaupt betroffen?

Kurz gesagt: fast jeder, der PostgreSQL mit einer „echten“ Locale betreibt. Nur zwei Konstellationen sind aus dem Schneider:

  • Datenbanken mit C– oder POSIX-Locale – dort wird schlicht nach Byte-Werten sortiert, und das ändert sich nie.
  • Reine Zahlen-Indizes – betroffen sind nur Indizes über Text-Spalten (text, varchar, char).

Wer diesen Tanz bei künftigen glibc-Sprüngen vermeiden möchte, kann langfristig auf ICU-Collations mit eingefrorener Version umstellen oder unkritische Spalten unter C-Collation führen. Das ist allerdings eine eigene Baustelle mit Dump/Restore – für den Moment nach dem Upgrade reicht: reindizieren, dann refreshen, in dieser Reihenfolge.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert