TL;DR: Wir haben ein Upgrade vermasselt und suchen Hilfe
Mit Home Assistant nutzen wir Discourse für unsere Community. Wir betreiben es mit der Methode discourse_docker auf einer EC2-Instanz bei AWS.
Als Open-Source-Projekt geriet die Wartung des Forums ins Hintertreffen, und wir landeten bei einer alten Version, die zuletzt Anfang 2019 aktualisiert wurde.
Um es noch schlimmer zu machen, hatten wir bei einem früheren Upgrade PostgreSQL auf Version 9.5 festgelegt, weil uns der benötigte Festplattenspeicher für ein Upgrade auf PostgreSQL 10 fehlte. Dieses Problem haben wir nie gelöst.
Zudem hatten wir einmal eine Änderung an der Cloudflare-Vorlage vorgenommen und diese ins Repository eingecheckt. Dadurch konnte sich der discourse_docker-Branch nicht automatisch auf die neueste Version aktualisieren.
Gestern haben wir uns entschlossen, das Upgrade durchzuführen …
Beim Migrieren der Datenbank stießen wir auf ein Problem: Es wurde eine Syntax verwendet, die mit 9.5 nicht kompatibel war:
== 20200429095034 AddTopicThumbnailInformation: migrating =====================
-- execute("ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n")
Das Problem mit der Festlegung auf Version 9.5 wurde uns schnell bewusst. Wir beschlossen daher, auf PostgreSQL 10 zu migrieren. Das funktionierte jedoch nicht, und wir erhielten folgenden Fehler:
I, [2020-06-12T00:30:55.448351 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 10
WARNING: Upgrading PostgresSQL would require an addtional 89M of disk space
Please free up some space, or expand your disk, before continuing.
Wir hatten 47 GB verfügbar, was seltsam war. Dann stellten wir fest, dass discourse_docker veraltet war, und aktualisierten es auf die neueste Version. Überraschung: PostgreSQL 12 war gerade erschienen.
Nachdem wir den Neuaufbau erneut ausgeführt hatten, erhielten wir diesmal diesen Fehler:
I, [2020-06-12T00:41:17.378129 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 12
WARNING: Upgrading PostgresSQL would require an addtional 92G of disk space
Please free up some space, or expand your disk, before continuing.
Das ist etwas mehr Speicherplatz, aber sicher. Lassen Sie uns unseren Festplattenspeicher einfach auf 300 GB erhöhen und es erneut ausführen.
Dieses Mal brach pg_upgrade während der Migration ab:
Restoring database schemas in the new cluster
template1
discourse
*failure* Consult the last few lines of "pg_upgrade_dump_16384.log" for the probable cause of the failure. Failure, exiting
Als wir die Datei pg_upgrade_dump_16384.log prüften, sahen wir folgenden Fehler:
pg_restore: creating VIEW "postgres_exporter.pg_stat_activity"
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 721; 1259 678554 VIEW pg_stat_activity postgres
pg_restore: [archiver (db)] could not execute query: ERROR: column pg_stat_activity.waiting does not exist
LINE 27: "pg_stat_activity"."waiting",
^
Command was:
-- For binary upgrade, must preserve pg_type oid
SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('678556'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type array oid
SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('678555'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_class oids
SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('678554'::pg_catalog.oid);
CREATE VIEW "postgres_exporter"."pg_stat_activity" AS
SELECT "pg_stat_activity"."datid",
"pg_stat_activity"."datname",
"pg_stat_activity"."pid",
"pg_stat_activity"."usesysid",
"pg_stat_activity"."usename",
"pg_stat_activity"."application_name",
"pg_stat_activity"."client_addr",
"pg_stat_activity"."client_hostname",
"pg_stat_activity"."client_port",
"pg_stat_activity"."backend_start",
"pg_stat_activity"."xact_start",
"pg_stat_activity"."query_start",
"pg_stat_activity"."state_change",
"pg_stat_activity"."waiting",
"pg_stat_activity"."state",
"pg_stat_activity"."backend_xid",
"pg_stat_activity"."backend_xmin",
"pg_stat_activity"."query"
FROM "pg_stat_activity";
Oh je.
An diesem Punkt beschlossen wir, einige Schritte zurückzugehen. Könnten wir das Forum einfach wieder hochfahren und im Nur-Lese-Modus betreiben, während wir uns um die Backup-Problematik kümmern? Wir schafften dies, indem wir einige Berechtigungsprobleme für sowohl postgres als auch redis behoben. Das Forum war dann wieder auf der alten Version online. Nicht alles funktioniert; beispielsweise führt der Aufruf von Admin → Benutzer → Gruppen zu diesem Fehler:
NoMethodError (undefined method `automatic_membership_retroactive' for #<Group:0x00007fcaca3045e8>)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
Der Rest scheint jedoch zu funktionieren.
An diesem Punkt entschieden wir, dass wir, da wir uns durch chown wieder zu einer funktionierenden Instanz durchkämpfen mussten, einfach eine neue Instanz starten und unser Backup importieren sollten.
Also starteten wir eine neue EC2-Instanz, führten die Einführungsanweisungen für discourse_docker aus und starteten unseren Import. Dann stießen wir auf ein seltsames Problem: Es konnte kein Index erstellt werden, da die Daten nicht den Eindeutigkeitsanforderungen des Index entsprachen:
ERROR: could not create unique index "index_incoming_domains_on_name_and_https_and_port"
DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
EXCEPTION: psql failed: DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
/var/www/discourse/lib/backup_restore/database_restorer.rb:95:in `restore_dump'
Als wir jedoch in die Rails-Konsole unserer laufenden Instanz sprangen, war es keine Duplikation:
[7] pry(main)> IncomingDomain.where(name: "homeassistant.home")
=> [#<IncomingDomain:0x000055e5cabc3760 id: 8648, name: "homeassistant.home", https: false, port: 8123>]
Dort stehen wir also gerade. Und wir sind ziemlich ratlos.
- Wir haben eine laufende Instanz mit einer schlechten Datenbank im Vergleich zum Ruby-Code, die nicht auf neuere PostgreSQL-Versionen migrieren kann.
- Wir haben ein Backup, das nicht in einer neuen Instanz importiert werden kann.
Wir haben untersucht, ob wir zu einem kostenpflichtigen gehosteten Discourse wechseln können. Da wir jedoch 3 Millionen Seitenaufrufe und eine Million Beiträge haben, ist das Enterprise-Pricing für uns zu große Verpflichtung.
Wir müssen also einen Ausweg finden. Vorzugsweise könnten wir unser Backup importieren, aber auch die Migration unserer alten Instanz wäre eine Lösung.
Hat jemand Ideen? Wir haben nichts dagegen, jemanden zu bezahlen, der uns hilft.