TL;DR:我们在升级中搞砸了,需要帮助
我们使用 Home Assistant 的 Discourse 来驱动我们的社区。我们在 AWS 的 EC2 实例上通过 discourse_docker 方法运行它。
作为一个开源项目,论坛维护被搁置了,我们最终停留在旧版本上,上次更新是在 2019 年初。
更糟糕的是,之前的升级中,由于没有足够的磁盘空间升级到 Postgres 10,我们将 Postgres 锁定在 9.5 版本。我们从未解决过这个问题。
此外,我们曾修改过 Cloudflare 模板并将其提交到代码库,这导致 discourse_docker 分支无法更新到最新版本。
昨天,我们决定进行升级……
在迁移数据库时,我们遇到了一个语法与 9.5 不兼容的问题:
== 20200429095034 AddTopicThumbnailInformation: migrating =====================
-- execute("ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n")
我们很快意识到锁定 9.5 的问题,于是决定迁移到 Postgres 10。但这失败了,我们收到了以下错误:
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.
我们还有 47G 的可用空间,这很奇怪。随后我们发现 discourse_docker 已过时,于是更新到最新版本。令人惊讶的是,Postgres 12 刚刚发布。
再次运行 rebuild 后,这次我们得到了以下错误:
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.
这需要的空间更多了,但没问题。我们将磁盘空间提升到 300G 并再次运行。
这次 pg_upgrade 在迁移过程中失败了:
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
当我们查看 pg_upgrade_dump_16384.log 文件时,发现了以下错误:
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";
哎呀。
于是我们决定退几步。能否先让论坛重新上线,并设置为只读模式,同时我们解决备份问题?我们通过修复 postgres 和 redis 的一些权限问题成功做到了这一点,论坛在旧版本上重新上线。不过并非所有功能都正常,例如访问 admin → user → groups 会报错:
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'
但其他功能似乎正常。
此时我们决定,既然不得不通过 chown 操作才让实例恢复运行,不如直接启动一个新实例并导入我们的备份。
于是我们启动了一个新的 EC2 实例,按照 discourse_docker 的入门指南操作,并开始导入备份。但随后遇到了一个奇怪的问题:由于数据不符合索引的唯一性要求,无法创建索引:
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'
但当我们进入运行中实例的 Rails 控制台时,发现数据并非重复:
[7] pry(main)> IncomingDomain.where(name: "homeassistant.home")
=> [#<IncomingDomain:0x000055e5cabc3760 id: 8648, name: "homeassistant.home", https: false, port: 8123>]
这就是我们目前的情况,有点不知所措。
- 我们有一个运行中的实例,其数据库与 Ruby 代码不匹配,无法迁移到更新的 Postgres 版本。
- 我们有一个备份,但无法导入到新实例中。
我们探索了是否可以使用付费托管的 Discourse 服务,但由于我们有 300 万页面浏览量和 100 万帖子,企业定价对我们来说负担太重。
因此,我们需要找到解决方案。最好能导入我们的备份,但如果能迁移旧实例也可以。
有人有任何想法吗?我们也不介意付费请人帮忙。