Help us learn about your current experience with the documentation. Take the survey.

Linux 包安装的 PostgreSQL 复制和故障排除

  • Tier: Premium, Ultimate
  • Offering: GitLab Self-Managed

在使用 PostgreSQL 复制和故障转移时,您可能会遇到以下问题。

Consul 和 PostgreSQL 更改未生效

由于潜在影响,gitlab-ctl reconfigure 只会重新加载 Consul 和 PostgreSQL,而不会重启服务。但是,并非所有更改都可以通过重新加载来激活。

要重启任一服务,请运行 gitlab-ctl restart SERVICE

对于 PostgreSQL,默认情况下重启主节点通常是安全的。自动故障转移默认为 1 分钟超时。只要数据库在此之前恢复,就不需要做其他操作。

在 Consul 服务器节点上,重要的是要以受控方式重启 Consul 服务

PgBouncer 错误 ERROR: pgbouncer cannot connect to server

运行 gitlab-rake gitlab:db:configure 时可能会遇到此错误,或者在 PgBouncer 日志文件中看到此错误。

PG::ConnectionBad: ERROR:  pgbouncer cannot connect to server

问题可能是您的 PgBouncer 节点的 IP 地址未包含在数据库节点的 /etc/gitlab/gitlab.rb 中的 trust_auth_cidr_addresses 设置中。

您可以通过检查主数据库节点上的 PostgreSQL 日志来确认这是否是问题所在。如果您看到以下错误,那么 trust_auth_cidr_addresses 就是问题所在。

2018-03-29_13:59:12.11776 FATAL:  no pg_hba.conf entry for host "123.123.123.123", user "pgbouncer", database "gitlabhq_production", SSL off

要解决此问题,请将 IP 地址添加到 /etc/gitlab/gitlab.rb 中。

postgresql['trust_auth_cidr_addresses'] = %w(123.123.123.123/32 <other_cidrs>)

重新配置 GitLab 以使更改生效。

Patroni 切换后 PgBouncer 节点未故障转移

由于影响 GitLab 16.5.0 之前版本的已知问题,在 Patroni 切换后,PgBouncer 节点的自动故障转移不会发生。在此示例中,GitLab 未能检测到暂停的数据库,然后尝试恢复一个未暂停的数据库:

INFO -- : Running: gitlab-ctl pgb-notify --pg-database gitlabhq_production --newhost database7.example.com --user pgbouncer --hostuser gitlab-consul
ERROR -- : STDERR: Error running command: GitlabCtl::Errors::ExecutionError
ERROR -- : STDERR: ERROR: ERROR:  database gitlabhq_production is not paused

为确保 Patroni 切换 成功,您必须使用以下命令在所有 PgBouncer 节点上手动重启 PgBouncer 服务:

gitlab-ctl restart pgbouncer

重新初始化副本

如果副本无法启动或重新加入集群,或者当它落后且无法赶上时,可能需要重新初始化副本:

  1. 检查复制状态 以确认需要重新初始化哪个服务器。例如:

    + Cluster: postgresql-ha (6970678148837286213) ------+---------+--------------+----+-----------+
    | Member                              | Host         | Role    | State        | TL | Lag in MB |
    +-------------------------------------+--------------+---------+--------------+----+-----------+
    | gitlab-database-1.example.com       | 172.18.0.111 | Replica | running      | 55 |         0 |
    | gitlab-database-2.example.com       | 172.18.0.112 | Replica | start failed |    |   unknown |
    | gitlab-database-3.example.com       | 172.18.0.113 | Leader  | running      | 55 |           |
    +-------------------------------------+--------------+---------+--------------+----+-----------+
  2. 登录到故障服务器并重新初始化数据库和复制。Patroni 会关闭该服务器上的 PostgreSQL,删除数据目录,并从头开始重新初始化:

    sudo gitlab-ctl patroni reinitialize-replica --member gitlab-database-2.example.com

    这可以在任何 Patroni 节点上运行,但请注意,不带 --membersudo gitlab-ctl patroni reinitialize-replica 会重启它运行的服务器。 您应该在故障服务器上本地运行它以减少意外数据丢失的风险。

  3. 监控日志:

    sudo gitlab-ctl tail patroni

重置 Consul 中的 Patroni 状态

重置 Consul 中的 Patroni 状态是一个可能具有破坏性的过程。请确保您首先有一个健康的数据库备份。

作为最后手段,您可以完全重置 Consul 中的 Patroni 状态。

如果您的 Patroni 集群处于未知或不良状态且没有节点可以启动,则可能需要这样做:

+ Cluster: postgresql-ha (6970678148837286213) ------+---------+---------+----+-----------+
| Member                              | Host         | Role    | State   | TL | Lag in MB |
+-------------------------------------+--------------+---------+---------+----+-----------+
| gitlab-database-1.example.com       | 172.18.0.111 | Replica | stopped |    |   unknown |
| gitlab-database-2.example.com       | 172.18.0.112 | Replica | stopped |    |   unknown |
| gitlab-database-3.example.com       | 172.18.0.113 | Replica | stopped |    |   unknown |
+-------------------------------------+--------------+---------+---------+----+-----------+

在删除 Consul 中的 Patroni 状态之前, 尝试解决 Patroni 节点上的 gitlab-ctl 错误

此过程会导致在第一个 Patroni 节点启动时重新初始化 Patroni 集群。

要重置 Consul 中的 Patroni 状态:

  1. 记录下之前是主节点的 Patroni 节点,或者应用程序认为当前是主节点的节点, 如果当前状态显示多个或没有:

    • 查看 PgBouncer 节点上的 /var/opt/gitlab/consul/databases.ini, 其中包含当前主节点的主机名。

    • 在所有数据库节点上查看 Patroni 日志 /var/log/gitlab/patroni/current(或旧的轮转和压缩日志 /var/log/gitlab/patroni/@40000*), 以查看集群最近将哪个服务器识别为主节点:

      INFO: no action. I am a secondary (database1.local) and following a leader (database2.local)
  2. 在所有节点上停止 Patroni:

    sudo gitlab-ctl stop patroni
  3. 重置 Consul 中的状态:

    /opt/gitlab/embedded/bin/consul kv delete -recurse /service/postgresql-ha/
  4. 启动一个 Patroni 节点,它会初始化 Patroni 集群以选举主节点。 强烈建议启动之前的主节点(在第一步中记录的), 以避免丢失可能因集群状态损坏而未复制的现有写入:

    sudo gitlab-ctl start patroni
  5. 启动所有其他作为副本加入 Patroni 集群的 Patroni 节点:

    sudo gitlab-ctl start patroni

如果您仍然遇到问题,下一步是恢复最后的健康备份。

Patroni 日志中关于 pg_hba.conf 条目为 127.0.0.1 的错误

Patroni 日志中的以下日志条目表明复制未正常工作,需要进行配置更改:

FATAL:  no pg_hba.conf entry for replication connection from host "127.0.0.1", user "gitlab_replicator"

要解决此问题,请确保回环接口包含在 CIDR 地址列表中:

  1. 编辑 /etc/gitlab/gitlab.rb

    postgresql['trust_auth_cidr_addresses'] = %w(<other_cidrs> 127.0.0.1/32)
  2. 重新配置 GitLab 以使更改生效。

  3. 检查所有副本是否已同步

错误:请求的起始点先于预写日志(WAL)刷新位置

Patroni 日志中的此错误表明数据库未进行复制:

FATAL:  could not receive data from WAL stream:
ERROR:  requested starting point 0/5000000 is ahead of the WAL flush position of this server 0/4000388

此示例错误来自最初配置错误的副本,并且从未进行过复制。

通过重新初始化副本来修复它。

Patroni 因 MemoryError 启动失败

Patroni 可能启动失败,记录错误和堆栈跟踪:

MemoryError
Traceback (most recent call last):
  File "/opt/gitlab/embedded/bin/patroni", line 8, in <module>
    sys.exit(main())
[..]
  File "/opt/gitlab/embedded/lib/python3.7/ctypes/__init__.py", line 273, in _reset_cache
    CFUNCTYPE(c_int)(lambda: None)

如果堆栈跟踪以 CFUNCTYPE(c_int)(lambda: None) 结尾,则此代码会触发 MemoryError, 如果 Linux 服务器已进行安全加固。

该代码会导致 Python 写入临时可执行文件,如果找不到文件系统来执行此操作,则会失败。例如,如果 /tmp 文件系统设置了 noexec,则会因 MemoryError 而失败(在问题中阅读更多)。

运行 gitlab-ctl 时的错误

Patroni 节点可能会进入 gitlab-ctl 命令失败且 gitlab-ctl reconfigure 无法修复节点的状态。

如果这恰逢 PostgreSQL 版本升级,请遵循不同的程序

一个常见症状是,如果数据库服务器启动失败,gitlab-ctl 无法确定它需要的安装信息:

Malformed configuration JSON file found at /opt/gitlab/embedded/nodes/<HOSTNAME>.json.
This usually happens when your last run of `gitlab-ctl reconfigure` didn't complete successfully.
Error while reinitializing replica on the current node: Attributes not found in
/opt/gitlab/embedded/nodes/<HOSTNAME>.json, has reconfigure been run yet?

类似地,节点文件(/opt/gitlab/embedded/nodes/<HOSTNAME>.json)应包含大量信息, 但可能只创建为:

{
  "name": "<HOSTNAME>"
}

以下修复过程包括重新初始化此副本: 此节点上 PostgreSQL 的当前状态将被丢弃:

  1. 关闭 Patroni 和(如果存在)PostgreSQL 服务:

    sudo gitlab-ctl status
    sudo gitlab-ctl stop patroni
    sudo gitlab-ctl stop postgresql
  2. 删除 /var/opt/gitlab/postgresql/data 以防其状态阻止 PostgreSQL 启动:

    cd /var/opt/gitlab/postgresql
    sudo rm -rf data

    请谨慎执行此步骤以避免数据丢失。 也可以通过重命名 data/ 来实现此步骤: 确保磁盘有足够空间用于主数据库的新副本, 并在修复副本后删除额外目录。

  3. 在 PostgreSQL 未运行的情况下,节点文件现在可以成功创建:

    sudo gitlab-ctl reconfigure
  4. 启动 Patroni:

    sudo gitlab-ctl start patroni
  5. 监控日志并检查集群状态:

    sudo gitlab-ctl tail patroni
    sudo gitlab-ctl patroni members
  6. 再次运行 reconfigure

    sudo gitlab-ctl reconfigure
  7. 如果 gitlab-ctl patroni members 表明需要,则重新初始化副本:

    sudo gitlab-ctl patroni reinitialize-replica

如果此程序不起作用且集群无法选举主节点, 还有另一种修复方法,这应该只 作为最后手段使用。

Patroni 副本上的 PostgreSQL 主版本升级失败

gitlab-ctl pg-upgrade 期间,Patroni 副本可能会陷入循环,升级失败。

一组症状示例如下:

  1. 定义了一个 postgresql 服务, 这通常不应该出现在 Patroni 节点上。它存在是因为 gitlab-ctl pg-upgrade 添加了它来创建新的空数据库:

    run: patroni: (pid 1972) 1919s; run: log: (pid 1971) 1919s
    down: postgresql: 1s, normally up, want up; run: log: (pid 1973) 1919s
  2. Patroni 在重新初始化副本时删除 /var/opt/gitlab/postgresql/data,PostgreSQL 在 /var/log/gitlab/postgresql/current 中生成 PANIC 日志条目:

    DETAIL:  Could not open file "pg_xact/0000": No such file or directory.
    WARNING:  terminating connection because of crash of another server process
    LOG:  all server processes terminated; reinitializing
    PANIC:  could not open file "global/pg_control": No such file or directory
  3. /var/log/gitlab/patroni/current 中,Patroni 记录以下内容。 本地 PostgreSQL 版本与集群主节点不同:

    INFO: trying to bootstrap from leader 'HOSTNAME'
    pg_basebackup: incompatible server version 12.6
    pg_basebackup: removing data directory "/var/opt/gitlab/postgresql/data"
    ERROR: Error when fetching backup: pg_basebackup exited with code=1

当 Patroni 集群处于以下状态时,此解决方法适用:

此解决方法通过将节点设置为使用新的 PostgreSQL 版本, 然后在升级主节点时创建的新集群中重新初始化 它来完成 Patroni 副本上的 PostgreSQL 升级:

  1. 在所有节点上检查集群状态,确认哪个是主节点 以及副本的状态

    sudo gitlab-ctl patroni members
  2. 副本:检查哪个版本的 PostgreSQL 处于活动状态:

    sudo ls -al /opt/gitlab/embedded/bin | grep postgres
  3. 副本:确保节点文件正确且 gitlab-ctl 可以运行。这会解决 如果副本也有任何运行 gitlab-ctl 的错误问题:

    sudo gitlab-ctl stop patroni
    sudo gitlab-ctl reconfigure
  4. 副本:重新链接 PostgreSQL 二进制文件到所需版本 以修复 incompatible server version 错误:

    1. 编辑 /etc/gitlab/gitlab.rb 并指定所需版本:

      postgresql['version'] = 13
    2. 重新配置 GitLab:

      sudo gitlab-ctl reconfigure
    3. 检查二进制文件是否已重新链接。为 PostgreSQL 分发的二进制文件在主版本之间有所不同, 通常会有少量错误的符号链接:

      sudo ls -al /opt/gitlab/embedded/bin | grep postgres
  5. 副本:确保 PostgreSQL 为指定版本完全重新初始化:

    cd /var/opt/gitlab/postgresql
    sudo rm -rf data
    sudo gitlab-ctl reconfigure
  6. 副本:可选地在另外两个终端会话中监控数据库:

    • 磁盘使用量随 pg_basebackup 运行而增加。使用以下命令跟踪 副本初始化进度:

      cd /var/opt/gitlab/postgresql
      watch du -sh data
    • 在日志中监控进程:

      sudo gitlab-ctl tail patroni
  7. 副本:启动 Patroni 以重新初始化副本:

    sudo gitlab-ctl start patroni
  8. 副本:完成后,从 /etc/gitlab/gitlab.rb 中删除硬编码版本:

    1. 编辑 /etc/gitlab/gitlab.rb 并删除 postgresql['version']

    2. 重新配置 GitLab:

      sudo gitlab-ctl reconfigure
    3. 检查正确的二进制文件已链接:

      sudo ls -al /opt/gitlab/embedded/bin | grep postgres
  9. 在所有节点上检查集群状态:

    sudo gitlab-ctl patroni members

如果需要,对其他副本重复此过程。

创建 PostgreSQL 副本时陷入循环

如果 PostgreSQL 副本似乎迁移但然后循环重启,请检查 副本和主服务器上的 /opt/gitlab-data/postgresql/ 文件夹权限。

您还可以在日志中看到此错误消息: could not get COPY data stream: ERROR: could not open file "<file>" Permission denied

其他组件的问题

如果您遇到本文档未概述的组件问题,请务必检查其特定文档页面的故障排除部分: