为 PostgreSQL 升级操作系统
Geo 不能用于将 PostgreSQL 数据库从一个操作系统迁移到另一个操作系统。如果您尝试这样做,辅助站点可能看起来已经 100% 复制,但实际上部分数据并未复制,从而导致数据丢失。这是因为 Geo 依赖于 PostgreSQL 流复制,而流复制会受到本文档中所述限制的影响。另请参阅 Geo 故障排查 - 检查操作系统区域设置数据兼容性。
如果您升级了运行 PostgreSQL 的操作系统,任何区域设置数据的更改都可能会损坏您的数据库索引。特别是,升级到 glibc 2.28 很可能会导致此问题。为避免此问题,请使用以下选项之一进行迁移,大致按复杂度排序:
在尝试任何迁移之前,请务必备份数据,并在类生产环境中验证迁移过程。如果停机时间可能是个问题,那么可以考虑在类生产环境中使用生产数据副本,为不同方法计时。
如果您运行的是一个横向扩展的 GitLab 环境,并且运行 PostgreSQL 的节点上没有其他服务,那么我们建议单独升级 PostgreSQL 节点的操作系统。为降低复杂性和风险,请勿将此过程与其他更改合并,尤其是那些不需要停机的更改,例如升级仅运行 Puma 或 Sidekiq 的节点的操作系统。
有关 GitLab 计划如何解决此问题的更多信息,请参阅 epic 8573。
备份与恢复
备份与恢复会重建整个数据库,包括索引。
-
安排一个计划的停机时间窗口。在所有节点上,停止不必要的 GitLab 服务:
gitlab-ctl stop gitlab-ctl start postgresql -
使用
pg_dump或 GitLab 备份工具(排除db以外的所有数据类型) 来备份 PostgreSQL 数据库(即仅备份数据库)。 -
在所有 PostgreSQL 节点上,升级操作系统。
-
在所有 PostgreSQL 节点上,升级操作系统后更新 GitLab 软件包源。
-
在所有 PostgreSQL 节点上,安装相同 GitLab 版本的新软件包。
-
从备份中恢复 PostgreSQL 数据库。
-
在所有节点上,启动 GitLab。
优点:
- 简单直接。
- 清除索引和表中的任何数据库膨胀,减少磁盘使用量。
缺点:
- 停机时间随数据库大小增加,在某个节点上会变得成问题。这取决于许多因素,但如果您的数据库超过 100 GB,则可能需要大约 24 小时。
备份与恢复,适用于包含 Geo 辅助站点的场景
-
安排一个计划的停机时间窗口。在所有站点的所有节点上,停止不必要的 GitLab 服务:
gitlab-ctl stop gitlab-ctl start postgresql -
在主站点,使用
pg_dump或 GitLab 备份工具(排除db以外的所有数据类型) 来备份 PostgreSQL 数据库(即仅备份数据库)。 -
在所有站点的所有 PostgreSQL 节点上,升级操作系统。
-
在所有站点的所有 PostgreSQL 节点上,升级操作系统后更新 GitLab 软件包源。
-
在所有站点的所有 PostgreSQL 节点上,安装相同 GitLab 版本的新软件包。
-
在主站点,从备份中恢复 PostgreSQL 数据库。
-
(可选)开始使用主站点,但这会有没有辅助站点作为热备的风险。
-
重新设置到辅助站点的 PostgreSQL 流复制。
-
如果辅助站点接收用户流量,则在启动 GitLab 之前,让只读副本数据库先完成追赶。
-
在所有站点的所有节点上,启动 GitLab。
重建所有索引
-
安排一个计划的停机时间窗口。在所有节点上,停止不必要的 GitLab 服务:
gitlab-ctl stop gitlab-ctl start postgresql -
在所有 PostgreSQL 节点上,升级操作系统。
-
在所有 PostgreSQL 节点上,升级操作系统后更新 GitLab 软件包源。
-
在所有 PostgreSQL 节点上,安装相同 GitLab 版本的新软件包。
-
在数据库控制台中,重建所有索引:
SET statement_timeout = 0; REINDEX DATABASE gitlabhq_production; -
重建数据库索引后,必须刷新所有受影响的排序规则的版本。要更新系统目录以记录当前的排序规则版本:
ALTER DATABASE gitlabhq_production REFRESH COLLATION VERSION; -
在所有节点上,启动 GitLab。
优点:
- 简单直接。
- 根据许多因素,可能比备份与恢复更快。
- 清除索引中的任何数据库膨胀,减少磁盘使用量。
缺点:
- 停机时间随数据库大小增加,在某个节点上会变得成问题。
重建所有索引,适用于包含 Geo 辅助站点的场景
-
安排一个计划的停机时间窗口。在所有站点的所有节点上,停止不必要的 GitLab 服务:
gitlab-ctl stop gitlab-ctl start postgresql -
在所有 PostgreSQL 节点上,升级操作系统。
-
在所有 PostgreSQL 节点上,升级操作系统后更新 GitLab 软件包源。
-
在所有 PostgreSQL 节点上,安装相同 GitLab 版本的新软件包。
-
在主站点的数据库控制台中,重建所有索引:
SET statement_timeout = 0; REINDEX DATABASE gitlabhq_production; -
重建数据库索引后,必须刷新所有受影响的排序规则的版本。要更新系统目录以记录当前的排序规则版本:
ALTER DATABASE <database_name> REFRESH COLLATION VERSION; -
如果辅助站点接收用户流量,则在启动 GitLab 之前,让只读副本数据库先完成追赶。
-
在所有站点的所有节点上,启动 GitLab。
仅重建受影响的索引
这与 GitLab.com 使用的方法类似。要了解有关此过程以及如何处理不同类型索引的更多信息,请参阅关于升级我们的 PostgreSQL 数据库集群的操作系统的博客文章。
-
安排一个计划的停机时间窗口。在所有节点上,停止不必要的 GitLab 服务:
gitlab-ctl stop gitlab-ctl start postgresql -
在所有 PostgreSQL 节点上,升级操作系统。
-
在所有 PostgreSQL 节点上,升级操作系统后更新 GitLab 软件包源。
-
在所有 PostgreSQL 节点上,安装相同 GitLab 版本的新软件包。
-
在数据库控制台中,重建每个受影响的索引:
SET statement_timeout = 0; REINDEX INDEX <index name> CONCURRENTLY; -
重建损坏的索引后,必须刷新排序规则。要更新系统目录以记录当前的排序规则版本:
ALTER DATABASE <database_name> REFRESH COLLATION VERSION; -
在所有节点上,启动 GitLab。
优点:
- 停机时间不会花费在重建未受影响的索引上。
缺点:
- 出错的机会更多。
- 需要具备 PostgreSQL 的专业知识,以处理迁移期间的意外问题。
- 保留了数据库膨胀。
仅重建受影响的索引,适用于包含 Geo 辅助站点的场景
-
安排一个计划的停机时间窗口。在所有站点的所有节点上,停止不必要的 GitLab 服务:
gitlab-ctl stop gitlab-ctl start postgresql -
在所有 PostgreSQL 节点上,升级操作系统。
-
在所有 PostgreSQL 节点上,升级操作系统后更新 GitLab 软件包源。
-
在所有 PostgreSQL 节点上,安装相同 GitLab 版本的新软件包。
-
在主站点的数据库控制台中,重建每个受影响的索引:
SET statement_timeout = 0; REINDEX INDEX <index name> CONCURRENTLY; -
重建损坏的索引后,必须刷新排序规则。要更新系统目录以记录当前的排序规则版本:
ALTER DATABASE <database_name> REFRESH COLLATION VERSION; -
现有的 PostgreSQL 流复制应将重建索引的更改复制到只读副本数据库。
-
在所有站点的所有节点上,启动 GitLab。
检查 glibc 版本
要查看使用的 glibc 版本,请运行 ldd --version。
下表显示了不同操作系统附带的 glibc 版本:
| 操作系统 | glibc 版本 |
|---|---|
| CentOS 7 | 2.17 |
| RedHat Enterprise 8 | 2.28 |
| RedHat Enterprise 9 | 2.34 |
| Ubuntu 18.04 | 2.27 |
| Ubuntu 20.04 | 2.31 |
| Ubuntu 22.04 | 2.35 |
| Ubuntu 24.04 | 2.39 |
例如,假设您正在从 CentOS 7 升级到 RedHat Enterprise 8。在这种情况下,在此升级后的操作系统上使用 PostgreSQL 需要使用上述两种方法之一,因为 glibc 从 2.17 升级到了 2.28。未能正确处理排序规则的更改会导致 GitLab 出现严重故障,例如 runner 无法拾取带标签的作业。
另一方面,如果 PostgreSQL 已经在 glibc 2.28 或更高版本上正常运行且没有问题,那么您的索引应该可以继续工作,无需进一步操作。例如,如果您已经在 RedHat Enterprise 8(glibc 2.28)上运行 PostgreSQL 一段时间,并希望升级到 RedHat Enterprise 9(glibc 2.34),则应该不存在与排序规则相关的问题。
验证 glibc 排序规则版本
对于 PostgreSQL 13 及更高版本,您可以使用以下 SQL 查询来验证您的数据库排序规则版本是否与您的系统匹配:
SELECT collname AS COLLATION_NAME,
collversion AS VERSION,
pg_collation_actual_version(oid) AS actual_version
FROM pg_collation
WHERE collprovider = 'c';排序规则匹配示例
例如,在 Ubuntu 22.04 系统上,一个索引正确的系统的输出如下所示:
gitlabhq_production=# SELECT collname AS COLLATION_NAME,
collversion AS VERSION,
pg_collation_actual_version(oid) AS actual_version
FROM pg_collation
WHERE collprovider = 'c';
collation_name | version | actual_version
----------------+---------+----------------
C | |
POSIX | |
ucs_basic | |
C.utf8 | |
en_US.utf8 | 2.35 | 2.35
en_US | 2.35 | 2.35
(6 rows)排序规则不匹配示例
另一方面,如果您从 Ubuntu 18.04 升级到 22.04 但没有重建索引,您可能会看到:
gitlabhq_production=# SELECT collname AS COLLATION_NAME,
collversion AS VERSION,
pg_collation_actual_version(oid) AS actual_version
FROM pg_collation
WHERE collprovider = 'c';
collation_name | version | actual_version
----------------+---------+----------------
C | |
POSIX | |
ucs_basic | |
C.utf8 | |
en_US.utf8 | 2.27 | 2.35
en_US | 2.27 | 2.35
(6 rows)流复制
索引损坏问题会影响 PostgreSQL 流复制。在允许对具有不同区域设置数据的副本进行读取之前,您必须重建所有索引或仅重建受影响的索引。
其他 Geo 变体
前面记录的升级程序并非一成不变。使用 Geo 时,由于存在冗余基础设施,因此可能有更多选择。您可以考虑进行修改以适应您的用例,但一定要权衡其带来的额外复杂性。以下是一些示例:
为了在主站点和其他辅助站点的操作系统升级期间发生灾难时,将一个辅助站点保留为热备:
- 将辅助站点的数据与主站点的更改隔离:暂停辅助站点。
- 在主站点上执行操作系统升级。
- 如果操作系统升级失败且主站点无法恢复,则提升辅助站点,将用户路由到该站点,然后稍后重试。这将使您失去一个最新的辅助站点。
为了在操作系统升级期间为用户提供 GitLab 的只读访问权限(部分停机):
- 在主站点上启用维护模式,而不是停止它。
- 提升辅助站点,但暂不将用户路由到该站点。
- 在提升后的站点上执行操作系统升级。
- 将用户路由到提升后的站点,而不是旧的主站点。
- 将旧的主站点设置为新的辅助站点。
即使辅助站点已经拥有数据库的只读副本,您也不能在提升之前升级其操作系统。如果您尝试这样做,由于索引损坏,辅助站点可能会错过某些 Git 仓库或文件的复制。请参阅流复制。