0x01 前言

我有多套 vCloud Director 以数据库高可用集群方式运行,即1个 primary 节点及2个 standby 节点。某天收到反馈提及用户通过 WEB GUI 创建虚拟机时页面卡住,创建任务一直停在”进行中”。

排查过程中发现的问题比预想的多:某个 standby 节点存储用完,导致 cell 服务故障,继而发现该节点的 PostgreSQL 流复制已经中断一个多月。

这篇文章记录磁盘异常与数据库重建的完整过程,供参考。

0x02 集群架构

本环境共三台 vCD Appliance(Photon OS 2.0,VCD 10.3.2.19375051),每台同时承载 vCD cell 与嵌入式 PostgreSQL,通过 **repmgr 4.4** 组成数据库 HA:

| 节点 | IP (eth0 / eth1) | repmgr Node ID | repmgr 角色 | 说明 |
| --- | --- | --- | --- | --- |
| vcd1-xx-xx-xx | vcd1-eth0 / vcd1-eth1 | 7893 | standby | 数据库 standby |
| vcd2-xx-xx-xx | vcd2-eth0 / vcd2-eth1 | 32572 | standby | 数据库 standby(本次故障节点)|
| vcd3-xx-xx-xx | vcd3-eth0 / vcd3-eth1 | 14185 | **primary** | 数据库主节点 |
                +---------------------+
                |   vcd3  (primary)   |
                |     vcd3-eth1       |
                +----------+----------+
                           | repmgr 流复制
          +----------------+----------------+
          |                                 |
+---------+---------+            +----------+----------+
| vcd1 (standby)    |            | vcd2 (standby)    |
|    vcd1-eth1      |            |    vcd2-eth1      |
+-------------------+            +-------------------+

VCD cell 访问数据库时,动态指向当前 primary 的 eth1 地址,所以故障切换时 cell 会自动切换数据库连接。

数据库信息如下:

  • 数据库:vcloud
  • 库用户:vcloud
  • repmgr 元数据库用户:repmgr

0x03 问题1 vcd2 存储满

0x03.1 现象

先正常查看集群数据库健康状态:

$ sudo -u postgres /opt/vmware/vpostgres/10/bin/repmgr \
    -f /opt/vmware/vpostgres/10/etc/repmgr.conf cluster show

 ID    | Name          | Role    | Status    | Upstream        | Location | Priority | Timeline | Connection string
-------+---------------+---------+-----------+-----------------+----------+----------+----------+----------------------------------------------------------------
 7893  | vcd1-xx-xx-xx | standby |   running | vcd3-xx-xx-xx   | default  | 100      | 2        | host=vcd1-eth1 user=repmgr dbname=repmgr connect_timeout=2
 14185 | vcd3-xx-xx-xx | primary | * running |                 | default  | 100      | 2        | host=vcd3-eth1 user=repmgr dbname=repmgr connect_timeout=2
 32572 | vcd2-xx-xx-xx | standby |   running | ! vcd3-xx-xx-xx | default  | 100      | 2        | host=vcd2-eth1 user=repmgr dbname=repmgr connect_timeout=2

WARNING: following issues were detected
  - node "vcd2-xx-xx-xx" (ID: 32572) is not attached to its upstream node "vcd3-xx-xx-xx" (ID: 14185)

 

vcd2 的 `!` 表示它没有成功 attach 到 primary。进一步查服务,发现 vcd2 的 vmware-vcd 服务为 failed 状态,根分区 100% 满,只剩 17M,Java cell 连日志都写不进去,所以 cell 起不来:

$ systemctl status vmware-vcd
* vmware-vcd.service - LSB: The VMware vCloud Director service
   Loaded: loaded (/etc/rc.d/init.d/vmware-vcd; generated; vendor preset: enabled)
  Drop-In: /etc/systemd/system/vmware-vcd.service.d
           `-10-aftervaos.conf
   Active: failed (Result: exit-code) since Wed 2026-08-19 07:52:17 UTC; 20min ago
     Docs: man:systemd-sysv-generator(8)
  Process: 943 ExecStart=/etc/rc.d/init.d/vmware-vcd start (code=exited, status=154)
    Tasks: 0 (limit: 4915)
   CGroup: /system.slice/vmware-vcd.service

$ journalctl -u vmware-vcd --no-pager -n 10
Aug 19 07:52:12 vcd2 systemd[1]: Starting LSB: The VMware vCloud Director service...
Aug 19 07:52:17 vcd2 vmware-vcd[943]: Starting vmware-vcd-watchdog: [FAILED]
Aug 19 07:52:17 vcd2 systemd[1]: vmware-vcd.service: Control process exited, code=exited status=154
Aug 19 07:52:17 vcd2 systemd[1]: Failed to start LSB: The VMware vCloud Director service.

$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        28G   26G   17M 100%  /

$ tail /opt/vmware/vcloud-director/logs/cell.log | head -20
log4j:ERROR Failed to flush writer,
log4j:ERROR Failed to flush writer,
log4j:ERROR Failed to flush writer,
log4j:ERROR Failed to flush writer

 

0x03.2 问题定位

根分区大目录排查:

$ du -xh --max-depth=1 / | sort -rh | head -10
26G  /
25G  /opt
1004M  /var
597M  /usr
14M  /etc
36K  /root
12K  /mnt

$ du -sh /opt/vmware/vcloud-director/data/activemq/defaultBroker
22G   /opt/vmware/vcloud-director/data/activemq/defaultBroker

$ find /opt/vmware/vcloud-director/data/activemq/defaultBroker -name 'activemq-data-*.amq' | wc -l
2195

 

罪魁祸首是 vcd2 上嵌入式 ActiveMQ Broker(KahaDB)的 journal 文件,activemq-data-*.amq 堆积 2195 个,每个 10MB,合计约 21.4GB。对比正常的 vcd1:

| 节点 | `defaultBroker/` 大小 | `.amq` 文件数 |
| --- | --- | --- |
| vcd1(正常) | 23M | 2 |
| vcd2(异常) | **22G** | **2195** |

 

而且这些文件从 2025年6起,每个月都在新增且从不回收。这说明该节点 KahaDB 的消息确认和 checkpoint 回收机制一直没生效。

说明:.amq 并不是普通日志,而是 ActiveMQ 持久化的 JMS 消息存储(KahaDB journal)。我用 strings 查看文件内容,里面基本都是 com.vmware.vcloud.common.configuration.impl.ConfigUpdatedMessage 这类 VCD 内部 JMS 消息对象。正常情况消息消费后会在 checkpoint 时清理旧 data 文件,但这里一直没清理。与之对应的 .bindings 、.tmp 文件也和这台异常节点一起堆积。

0x03.3 清理

确认当前 cell 已停止服务,defaultBroker 没有被进程占用,也没有 lock 后,为把 2026 年 8 月 1 日之前修改过的 journal 文件全部删除:

$ cd /opt/vmware/vcloud-director/data/activemq/defaultBroker

# 1) 先记录将被删除的文件清单,便于追溯(数量与总大小)
$ find . -maxdepth 1 ! -newermt '2026-08-01' \
    \( -name '*.amq' -o -name '*.bindings' -o -name '*.tmp' \) \
    -printf '%s %f\n' > /root/activemq_deleted_20260819.list
$ wc -l /root/activemq_deleted_20260819.list
2196
$ awk '{s+=$1} END {printf "%.2f GB\n", s/1073741824}' /root/activemq_deleted_20260819.list
20.61 GB

# 2) 执行删除
$ find . -maxdepth 1 ! -newermt '2026-08-01' \
    \( -name '*.amq' -o -name '*.bindings' -o -name '*.tmp' \) -delete

# 3) 确认清理结果与空间
$ find . -maxdepth 1 -name '*.amq' | wc -l
91
$ du -sh .
917M   .
$ df -h /
/dev/sda3  28G  5.1G  21G  20%  /

 

释放约 21GB,根分区从 100% 回落到 20%。随后启动 cell:

$ systemctl start vmware-vcd

$ systemctl is-active vmware-vcd
active

$ curl -sk --max-time 10 -o /dev/null -w 'HTTP %{http_code} (%{time_total}s)\n' https://vcd2-eth0/api/server_status
HTTP 200 (0.030569s)

 

cell 恢复正常。

0x04 问题2 vcd2 数据库滞后

0x04.1 standby follow 无法追平

cell 起来后,尝试用 repmgr 让 vcd2 重新跟随 primary:

$ sudo -u postgres /opt/vmware/vpostgres/10/bin/repmgr \
    -f /opt/vmware/vpostgres/10/etc/repmgr.conf standby follow --dry-run

NOTICE: attempting to find and follow current primary
INFO: connected to node 14185, checking for current primary
INFO: follow target is primary node "vcd3-xx-xx-xx" (ID: 14185)
INFO: replication connection to the local node was successful
INFO: replication connection to the follow target node was successful
INFO: local and follow target system identifiers match
DETAIL: system identifier is 7065916388744459236
INFO: timelines are same, this server is not ahead
DETAIL: local node lsn is A85/2A4A83D8, follow target lsn is 218E/6B785D98
INFO: prerequisites for executing STANDBY FOLLOW are met

$ sudo -u postgres /opt/vmware/vpostgres/10/bin/repmgr \
    -f /opt/vmware/vpostgres/10/etc/repmgr.conf standby follow --log-to-file

[2026-08-19 08:31:46] [NOTICE] attempting to find and follow current primary
[2026-08-19 08:31:46] [INFO] timelines are same, this server is not ahead
[2026-08-19 08:31:46] [NOTICE] setting node 32572's upstream to node 14185
[2026-08-19 08:31:46] [NOTICE] restarting server using "sudo /usr/bin/systemctl restart vpostgres"
[2026-08-19 08:32:21] [NOTICE] STANDBY FOLLOW successful
[2026-08-19 08:32:21] [DETAIL] standby attached to upstream node "vcd3-xx-xx-xx" (ID: 14185)

 

repmgr 元数据更新成功,但 cluster show 依然显示 vcd2 没 attach,仍有感叹号 “!”,看 PostgreSQL 日志:

$ tail /var/vmware/vpostgres/current/pgdata/log/postgresql-*.log
FATAL: could not receive data from WAL stream:
  ERROR:  requested WAL segment 0000000200000A850000002A has already been removed
LOG:  received SIGHUP, reloading configuration files
LOG:  started streaming WAL from primary at A85/2A000000 on timeline 2
FATAL: could not receive data from WAL stream:
  ERROR:  requested WAL segment 0000000200000A850000002A has already been removed

0x04.2 定位问题

vcd2 需要的旧 WAL 段 0000000200000A850000002A 在 primary 上早已被回收,所以无法增量追赶。翻日志发现这个断档不是这次磁盘故障造成的,而是从 7 月 21 日 00:00 就开始每天午夜都重试失败:

2026-07-21 00:00:04.673 UTC [29870] FATAL: requested WAL segment 0000000200000A850000002A has already been removed
2026-07-22 00:00:04.611 UTC [13940] FATAL: requested WAL segment 0000000200000A850000002A has already been removed
2026-07-23 00:00:03.536 UTC [28434] FATAL: requested WAL segment 0000000200000A850000002A has already been removed
2026-07-28 00:00:01.898 UTC [14313] FATAL: requested WAL segment 0000000200000A850000002A has already been removed
2026-07-31 00:00:04.884 UTC [25614] FATAL: requested WAL segment 0000000200000A850000002A has already been removed
2026-08-01 00:00:04.526 UTC [9439]  FATAL: requested WAL segment 0000000200000A850000002A has already been removed
2026-08-07 00:00:04.761 UTC [21975] FATAL: requested WAL segment 0000000200000A850000002A has already been removed

 

也就是说 vcd2 的数据库副本滞后约一个月,等于一个过期快照。standby follow 只能用来追差距不大且未 diverged 的 standby。当 WAL 已断档,就只能全量重建。

repmgr node status 也印证了滞后量:Replication lag 显示一个异常大的秒数,Last received LSN 长时间停在 A85/2A000000 不动。

0x04.3 全量重建

流程参考 VMware 官方 “Recover from VMware Cloud Director Appliance Standby Cell Failure”,本环境只有 vcd2 故障,不需要处理 primary 和 vcd1:

# 1) 停掉 vcd2 的 cell 与数据库
$ systemctl stop vmware-vcd

$ systemctl stop vpostgres

$ systemctl is-active vmware-vcd vpostgres
inactive
inactive

# 2) 备份旧数据目录
$ mv /var/vmware/vpostgres/current/pgdata \
     /var/vmware/vpostgres/pgdata.bak.$(date +%Y%m%d_%H%M%S)

$ ls -ld /var/vmware/vpostgres/pgdata.bak.*
drwx------ 20 postgres users 4096 Aug 19 08:39 /var/vmware/vpostgres/pgdata.bak.20260819_084020

$ du -sh /var/vmware/vpostgres/pgdata.bak.20260819_084020
17G   /var/vmware/vpostgres/pgdata.bak.20260819_084020

# 3) 从 primary(eth1 vcd3-eth1)全量 clone
$ su - postgres -c "/opt/vmware/vpostgres/current/bin/repmgr \
    -d 'host=vcd3-eth1 user=repmgr dbname=repmgr' \
    -f /opt/vmware/vpostgres/current/etc/repmgr.conf standby clone"

NOTICE: destination directory "/var/vmware/vpostgres/current/pgdata" provided
INFO: connecting to source node
DETAIL: connection string is: user=repmgr dbname=repmgr host=vcd3-eth1
DETAIL: current installation size is 2199 MB
NOTICE: checking for available walsenders on the source node (2 required)
NOTICE: checking replication connections can be made to the source server (2 required)
INFO: creating directory "/var/vmware/vpostgres/current/pgdata"...
NOTICE: starting backup (using pg_basebackup)...
INFO: executing:
  /opt/vmware/vpostgres/current/bin/pg_basebackup -l "repmgr base backup" \
    -D /var/vmware/vpostgres/current/pgdata \
    -d 'user=repmgr dbname=repmgr host=vcd3-eth1' -X stream
NOTICE: standby clone (using pg_basebackup) complete
NOTICE: you can now start your PostgreSQL server
HINT: after starting the server, you need to re-register this standby with "repmgr standby register --force"

# 4) 启动数据库,确认进入 recovery(standby)模式
$ systemctl start vpostgres

$ systemctl is-active vpostgres
active

$ su - postgres -c "/opt/vmware/vpostgres/current/bin/psql -d postgres -tAc 'select pg_is_in_recovery();'"
t

# 检查 clone 生成并指向 primary 的 recovery.conf
$ cat /var/vmware/vpostgres/current/pgdata/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=repmgr host=vcd3-eth1 application_name=''vcd2-xx-xx-xx'' connect_timeout=2'
recovery_target_timeline = 'latest'

# 5) 再次核验 node status
$ su - postgres -c "/opt/vmware/vpostgres/10/bin/repmgr \
    -f /opt/vmware/vpostgres/10/etc/repmgr.conf node status"

Node "vcd2-xx-xx-xx":
    PostgreSQL version: 10.17
    Total data size: 2198 MB
    Role: standby
    Upstream node: vcd3-xx-xx-xx (ID: 14185)
    Replication lag: 0 seconds
    Last received LSN: 218E/887BA470
    Last replayed LSN: 218E/887BA470

# 6) 启动 cell
$ systemctl start vmware-vcd

$ curl -sk --max-time 10 -o /dev/null -w 'HTTP %{http_code}\n' https://vcd2-eth0/api/server_status
200

 

最终验证集群状态:

$ sudo -u postgres /opt/vmware/vpostgres/10/bin/repmgr \
    -f /opt/vmware/vpostgres/10/etc/repmgr.conf cluster show

 ID    | Name          | Role    | Status    | Upstream      | Location | Priority | Timeline | Connection string
-------+---------------+---------+-----------+---------------+----------+----------+----------+----------------------------------------------------------------
 7893  | vcd1-xx-xx-xx | standby |   running | vcd3-xx-xx-xx | default  | 100      | 2        | host=vcd1-eth1 user=repmgr dbname=repmgr connect_timeout=2
 14185 | vcd3-xx-xx-xx | primary | * running |               | default  | 100      | 2        | host=vcd3-eth1 user=repmgr dbname=repmgr connect_timeout=2
 32572 | vcd2-xx-xx-xx | standby |   running | vcd3-xx-xx-xx | default  | 100      | 2        | host=vcd2-eth1 user=repmgr dbname=repmgr connect_timeout=2

 

不再有 “!” 标记,三节点全部健康,vcd2 复制滞后为 0。

0x05 结语

这次排障信息量不小,归纳几个容易踩的点和经验:

嵌入式 ActiveMQ KahaDB 会撑爆根分区。遇到 cell 莫名起不来he 日志刷 log4j:ERROR Failed to flush writer,先检查存储情况,再检查 /opt/vmware/vcloud-director/data/activemq/defaultBroker 。考虑清理旧的 journal 文件,包含:activemq-data-*.amq、过期的 .bindings、.tmp,前提是确认 cell 已停止、目录无进程占用且无 lock。

repmgr standby follow 不是万能的。requested WAL segment 0000000200000A850000002A has already been removed 一出现,就说明 standby 落后太多。primary 的 WAL 已被回收,直接全量 standby clone 重建,别在 follow 上反复耗时间。

要做好健康状态监控。vcd2 的流复制其实断了一个月,是因为没人看 repmgr 的 “!” 标记和每天重试的日志,才拖到这次一起暴露。建议对 repmgr 心跳和cell 服务状态做监控告警。