This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
---
|
||||
title: 2026-09-25 DRBD quorum 抖动与 sandbox 控制面中断
|
||||
last_reviewed: 2026-09-25
|
||||
---
|
||||
|
||||
# 2026-09-25 DRBD quorum 抖动与 sandbox 控制面中断
|
||||
|
||||
状态:服务已恢复;事故机制已确认,资源争用的具体瓶颈与预防性整改仍待验证。
|
||||
时间统一使用 UTC。报告依据当日 PVE/VyOS/guest 现场日志、相关操作会话和未提交 IaC;
|
||||
不是全量数据完整性审计,也不把短期恢复等同于根因消除。
|
||||
|
||||
## 结论
|
||||
|
||||
共享 PostgreSQL 的承载准备在 17:12 为 CT150、CT151 新建 16 GiB、32 GiB HDD DRBD
|
||||
数据卷,两卷初始同步重叠。随后多个既有 DRBD 资源出现 PingAck 超时和 quorum 丢失。
|
||||
sandbox1 根卷在 17:15:49 因 I/O 错误中止 ext4 journal、进入只读,PostgreSQL 主库和
|
||||
本机 K3s 退出;sandbox2 K3s 也失去数据库连接。VyOS HAProxy 摘除了不可连接的后端,
|
||||
从客户端看起来像 LB 故障。etcd CT150 的 SSD 根卷在 17:16:52 也发生同类故障。
|
||||
|
||||
**已确认的直接故障机制**是 DRBD 失去 quorum 后按 `on-no-quorum=io-error` 返回错误,
|
||||
引发 ext4 只读和上层服务中断。**最有证据支持的触发因素**是新 HDD 卷并发初始同步期间的
|
||||
共享资源压力;尚无故障时段的链路队列、丢包、磁盘延迟和 CPU 调度证据,不能定论为
|
||||
某条链路打满、某块磁盘损坏或唯一由 resync 流量造成。
|
||||
|
||||
这次更接近故障的操作是“创建数据卷并触发复制”,不是 15:30–15:32 已完成的 etcd
|
||||
rootfs 迁移。新 shared PostgreSQL 当时尚未启动,未迁移现有 CNPG 或 sandbox 数据库;
|
||||
影响经共享底层存储扩散到原有服务。
|
||||
|
||||
## 影响与恢复边界
|
||||
|
||||
| 对象 | 已观察到的影响 | 恢复证据 |
|
||||
| --- | --- | --- |
|
||||
| sandbox PostgreSQL,`10.60.0.1:5432` | 主库 `10.60.0.11` 停止监听,LB 无可用 backend | 原主库 crash recovery 完成;sandbox2 streaming/sync,采样 replay lag=0 |
|
||||
| sandbox K3s,`10.60.0.13:6443` | 两个 API 后端拒绝连接,控制面不可用 | 两个直连 API 与 VIP `/readyz=ok`;两节点和全部 Pod Ready |
|
||||
| OpenSandbox,`10.60.0.13:8080` | 健康入口仍可返回 200;依赖 K3s 的生命周期操作受控制面中断影响 | `/health` healthy;本轮未实际创建/销毁 sandbox,不能用 health 替代业务验收 |
|
||||
| shared etcd CT150 | SSD rootfs `emergency_ro`,成员无法正常服务,触发无 leader/频繁选举告警 | 另一会话完成离线修复,记录三成员 endpoint healthy、Raft term/index 一致 |
|
||||
| 其他 DRBD 资源 | pve1 在限定窗口记录 11 个资源共 43 次 quorum 丢失 | 尚未逐项完成 guest/应用层影响审计,不能说其他服务均未受影响 |
|
||||
|
||||
API 全后端不可用从 HAProxy 17:16:01 告警可确认;约 17:49 已有可用 API,
|
||||
约 17:51 完成双后端、节点与 Pod 验收。控制面中断约 33 分钟,完整恢复约 35 分钟。
|
||||
恢复后的复制和服务检查未发现新的异常,但不能据此证明中断期间全部业务请求成功或零数据丢失。
|
||||
数据库日志曾记录同步等待取消及“本地已提交、可能尚未复制”,未逐事务审计;未执行 WAL reset、
|
||||
standby 提升、数据库重建或恢复旧备份。
|
||||
|
||||
## 变更范围与存储映射
|
||||
|
||||
| 用途 | PVE/容器 | DRBD resource | 设备 | 存储池/大小 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 既有 sandbox1 根盘,包含 K3s datastore 主库 | pve1 / CT148 | `pm-6d8bee62` | `drbd1007` | `pve-rg-hdd` / 32 GiB |
|
||||
| etcd-pve1 根盘 | pve1 / CT150 | `pm-d1d1f3ea` | `drbd1008` | `pve-rg` SSD / 8 GiB |
|
||||
| 新 PG standby 数据盘 | pve1 / CT150 mp0 | `pm-af21c43d` | `drbd1011` | `pve-rg-hdd` / 16 GiB |
|
||||
| 新 pgBackRest 仓库盘 | pve2 / CT151 mp0 | `pm-de86804d` | `drbd1012` | `pve-rg-hdd` / 32 GiB |
|
||||
|
||||
17:12:20,pve1 作为 SyncSource 向 pve3 同步 CT150 新盘;17:12:56,pve1 又作为
|
||||
SyncTarget 从 pve2 接收 CT151 新盘。容器操作串行不代表底层复制串行,也不代表不同
|
||||
SSD/HDD 池具有独立的网络、宿主调度或 I/O 故障域。
|
||||
|
||||
## 时间线
|
||||
|
||||
| UTC | 事件与证据 |
|
||||
| --- | --- |
|
||||
| 15:30:16–15:31:09 | CT150 `move_volume` 完成,PVE 任务 OK;`local-lvm` → `pve-rg` |
|
||||
| 15:31:32–15:32:11 | CT151 同类迁移完成;会话随后确认三 etcd 端点健康 |
|
||||
| 17:09:14 | PG 会话说明即将创建独立 HDD mp0、增加内存预算,不启动 PG |
|
||||
| 17:11:46 | 执行 `ansible-playbook pve-storage.yml` |
|
||||
| 17:12:20 / 17:12:56 | 两个新 HDD 资源分别开始 DRBD 初始同步,发生重叠 |
|
||||
| 17:14:00 | 本报告 17:10–17:55 pve1 内核窗口内首条 `quorum( yes -> no )`;对象为既有 `pm-59a94edd` |
|
||||
| 17:14:09 | PG 会话报告承载准备完成、etcd 健康;未包含 DRBD 同步完成和跨服务检查 |
|
||||
| 17:15:47–17:15:48 | sandbox1 根卷先后丢失 pve3、pve2 连接,quorum yes→no |
|
||||
| 17:15:49 | `drbd1007` 写入错误、MMP 写失败、journal abort、只读;PG 启动控制命令报 I/O error,K3s SIGBUS |
|
||||
| 17:15:54 | HAProxy 报 sandbox1 API 和 PostgreSQL 后端 DOWN |
|
||||
| 17:16:01 | sandbox2 API 后端也 DOWN,K3s backend 无可用服务器 |
|
||||
| 17:16:52 | CT150 `drbd1008` 失去 quorum,ext4 进入只读 |
|
||||
| 17:18:53 | PG 会话发现 CT150 只读,暂停后续部署;另两个 etcd 成员健康 |
|
||||
| 17:20:27 | 维护者在 PG 会话提供 `SharedEtcdNoLeader` 实际通知 |
|
||||
| 17:20–17:25 | 准备限速;先遇到 playbook 路径错误,随后遇到 YAML 条件表达式类型错误,修正后重跑 |
|
||||
| 17:23:39 | 该内核窗口内最后一条 quorum 丢失;之后仍有 PingAck 超时,不能写成“限速后才停止 quorum 丢失” |
|
||||
| 17:24:37 | Alertmanager 会话获知 etcd 正在另一路调整,结束该会话对 etcd 的排查 |
|
||||
| 17:25:58 | 会话收到限速成功结果,两主机各 changed=1;新卷 `c-max-rate=10240` |
|
||||
| 17:25:59–17:28:11 | CT150 停机、离线修复、重新启动;约 17:30 报告三成员健康 |
|
||||
| 17:31:21 / 17:33:38 | CT151 / CT150 新数据卷分别完成 DRBD 同步,内核标记 resync-finished |
|
||||
| 17:42 起 | 维护者报告 sandbox LB 异常,本会话开始排查 |
|
||||
| 17:43–17:46 | 确认 HAProxy 正常、后端故障;定位 sandbox1 根盘 emergency_ro 和原始 quorum/I/O 日志 |
|
||||
| 17:46:41–17:46:49 | CT148 正常关机完成 |
|
||||
| 17:47–17:48 | `pct fsck 148 --device rootfs --force 1` 恢复 journal、清理 orphan inode;只读 `e2fsck -fn` 五阶段通过、返回 0 |
|
||||
| 17:48:40–17:48:44 | CT148 启动;根盘恢复 rw 且无 emergency_ro |
|
||||
| 17:49:04 / 17:49:08 | 原 PG 主库恢复接收连接;sandbox2 恢复同步 standby |
|
||||
| 17:50:40 左右 | sandbox2 K3s 在重启服务后恢复 API;此前旧进程卡在故障期间的启动/关闭状态 |
|
||||
| 约 17:51 | 两个 API 和 VIP readyz 通过、两节点及全部 Pod Ready、复制 lag=0 |
|
||||
| 17:53:49 | 两个新卷现场复核均 Established/UpToDate,限速属性和运行配置仍为 10240 |
|
||||
|
||||
宿主默认 journal 展示曾为 UTC+9,guest/VyOS 使用 UTC。初次用 UTC 字面时间过滤宿主
|
||||
本地日志没有找到错误;后来用 `journalctl --utc` 和明确 UTC 时间窗口纠正。上表不使用
|
||||
未经转换的 `Sep 26 02:xx` 作为独立事故时间。
|
||||
|
||||
## 故障机制与变更保护缺口
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[新增两个 HDD 数据卷] --> B[初始同步重叠]
|
||||
B -. 资源压力为待证实触发因素 .-> C[多个 DRBD 对端 PingAck 超时]
|
||||
C --> D[既有卷失去 majority quorum]
|
||||
D --> E[on-no-quorum=io-error]
|
||||
E --> F[ext4 journal abort / emergency_ro]
|
||||
F --> G[sandbox PostgreSQL 与本机 K3s 退出]
|
||||
G --> H[另一 K3s 失去 datastore / API 中断]
|
||||
H --> I[HAProxy 后端均 DOWN]
|
||||
F --> J[shared etcd 单成员异常]
|
||||
```
|
||||
|
||||
1. **变更验收停在容器/etcd 层。** `serial: 1` 和 endpoint health 只限制 Ansible 的
|
||||
容器操作顺序;未等待前一 DRBD 新卷完全同步,所以后台复制仍重叠。
|
||||
2. **未把新卷创建视为共享基础设施变更。** 新数据库尚未运行、卷内没有业务数据,
|
||||
仍会发生全卷复制并影响现有资源。仅检查新服务健康不能限制影响范围。
|
||||
3. **恢复检查范围过窄。** 首轮识别并恢复 CT150 后,未沿同批 quorum/I/O 日志
|
||||
核查 CT148 等既有消费者;sandbox 控制面继续故障,直至维护者再次报告。
|
||||
4. **监控缺少依赖链覆盖。** Alertmanager 通知当天已打通,etcd 实际告警送达;
|
||||
不能归因于“没有通知”。另一会话的盘点发现告警主要覆盖监控自身及 shared etcd,
|
||||
尚缺可证明有效的跨资源 DRBD、文件系统异常、sandbox API 外部可用性覆盖。
|
||||
`/health=200` 与单节点 Ready 也不足以证明两个 API 后端健康。
|
||||
5. **紧急缓解执行有延迟。** 限速 playbook 首次工作目录错误、随后条件被 YAML
|
||||
解析成非字符串,两次均在配置变更前失败;直到 17:25:58 才有成功回执。
|
||||
|
||||
限速后短期稳定且最终同步完成支持资源压力假设,但缺少控制变量;本次最后一次 quorum
|
||||
丢失早于成功限速,不能把时间相关性写成严格因果证明。现有 `pve-storage.yml` 已补入
|
||||
限速任务,但位于 `pct set --mp0` **之后**;初始同步在创建卷时已经开始,仍存在未限速
|
||||
窗口,并且仍缺 DRBD 同步完成屏障。此报告没有擅自更改这些并行工作中的实现。
|
||||
|
||||
## 已完成处置与验收
|
||||
|
||||
- PG/etcd 会话:仅为两个新卷设置资源级 `DrbdOptions/PeerDevice/c-max-rate=10240`
|
||||
(配置的自适应同步上限 10 MiB/s),记录幂等复跑无变更;CT150 离线修复后恢复三端点健康。
|
||||
- 本会话:确认 CT148 stopped、卷身份/未挂载、副本 UpToDate/quorum 后,使用 PVE 安全自动
|
||||
fsck;返回 1 表示已修复,随后独立只读完整检查返回 0,再启动原容器。
|
||||
- PostgreSQL 自行回放 WAL 并恢复原角色;未切主。sandbox2 K3s 在数据库恢复后仍卡住,
|
||||
仅重启该 K3s 服务,未重启或提升它的 PostgreSQL。
|
||||
- 两个直连 API 与 VyOS VIP `/readyz` 均为 ok;全部 Pod Ready;所有相关 HAProxy
|
||||
后端 UP/L4OK;OpenSandbox `/health` healthy;目标根卷恢复正常 rw。
|
||||
- 未修改 VyOS LB、全局 DRBD 协议/quorum/超时或集群网络。VyOS 最新提交及生成配置仍为
|
||||
9 月 18 日,最近两次 LB 变更仅新增 OpenSandbox 入口并调整其超时。
|
||||
|
||||
## 后续整改与关闭标准
|
||||
|
||||
下列项目是待办,不代表已获执行或发布授权;责任人/issue 由维护者分配。
|
||||
|
||||
| 优先级 | 项目 | 验收条件 |
|
||||
| --- | --- | --- |
|
||||
| P0 | 审计同批受影响 DRBD 资源对应 guest/应用 | 11 个资源逐一映射并记录文件系统、服务和数据层状态,不能只看 DRBD UpToDate |
|
||||
| P0 | 新卷创建前实施同步预算,新增 DRBD 同步屏障 | 第一字节同步前限额已生效;全部所需副本 UpToDate/Established 才允许下一卷;超时/异常停止推进 |
|
||||
| P0 | 扩大存储变更前后健康检查 | 验证已有 sandbox API、datastore、etcd 等消费者;新增 quorum loss、I/O 错误或只读即中止变更 |
|
||||
| P1 | 采集并定位实际瓶颈 | 对齐三宿主网络丢包/队列、吞吐、磁盘 await、CPU/PSI、DRBD 状态;无证据不直接扩大 ping timeout |
|
||||
| P1 | 补齐可操作告警 | DRBD quorum/peer、ext4 emergency_ro、数据库与 API 外部探测、LB 零后端,并演练真实通知链路 |
|
||||
| P1 | 恢复后业务验收与数据检查 | 对现有 sandbox 生命周期操作做受控验收,核对 PG 数据/备份和应用影响,单独报告不能验证的 RPO |
|
||||
| P1 | 复核共享故障域与同步总预算 | 同时覆盖多个 resource/peer;区分 SSD/HDD 池和物理网络/宿主故障域;设计限速或隔离方案后再测试 |
|
||||
| P2 | 标准化取证与并行变更交接 | 时间统一 UTC;事故期间共享受影响资源表、执行日志和完成边界;先 syntax/check,再执行缓解 playbook |
|
||||
|
||||
关闭本次根因整改需完成:跨资源影响审计、同步前预算与屏障验证、消费者健康保护、
|
||||
足够覆盖复制全过程的稳定性观察。当前只可宣称 **sandbox 服务恢复**。
|
||||
|
||||
## 证据与来源
|
||||
|
||||
### 现场关键摘录
|
||||
|
||||
```text
|
||||
17:12:20 drbd pm-af21c43d/0 drbd1011 pve3: Began resync as SyncSource
|
||||
17:12:56 drbd pm-de86804d/0 drbd1012 pve2: Began resync as SyncTarget
|
||||
17:15:47 drbd pm-6d8bee62 pve3: PingAck did not arrive in time.
|
||||
17:15:48 drbd pm-6d8bee62 pve2: PingAck did not arrive in time.
|
||||
17:15:48 drbd pm-6d8bee62/0 drbd1007: quorum( yes -> no )
|
||||
17:15:49 EXT4-fs error (device drbd1007): kmmpd:181: Error writing to MMP block
|
||||
17:15:49 Aborting journal on device drbd1007-8.
|
||||
17:15:49 EXT4-fs (drbd1007): Remounting filesystem read-only
|
||||
17:16:52 drbd pm-d1d1f3ea/0 drbd1008: quorum( yes -> no )
|
||||
17:16:52 EXT4-fs (drbd1008): Remounting filesystem read-only
|
||||
17:31:21 drbd pm-de86804d/0 drbd1012 pve2: repl( SyncTarget -> Established ) [resync-finished]
|
||||
17:33:38 drbd pm-af21c43d/0 drbd1011 pve3: pdsk( Inconsistent -> UpToDate ) repl( SyncSource -> Established ) [resync-finished]
|
||||
```
|
||||
|
||||
上述为 pve1 内核摘录,已省略重复前缀。43 次 quorum 丢失统计范围为 pve1 的
|
||||
`2026-09-25 17:10:00 UTC` 至 `17:55:00 UTC`,不是三节点全集群事件数。
|
||||
资源为 `pm-1f83b001`、`pm-57eb0cd7`、`pm-59a94edd`、`pm-6d8bee62`、
|
||||
`pm-7ad1a714`、`pm-a58b5f08`、`pm-cbba8c9d`、`pm-d1d1f3ea`、
|
||||
`pm-d4c12a89`、`pm-f21d1da3`、`vm-101-cloudinit`。
|
||||
|
||||
可复核入口:宿主 `journalctl --utc -k --since '2026-09-25 17:10:00 UTC'
|
||||
--until '2026-09-25 17:55:00 UTC'`、`pvenode task list`、目标 `drbdsetup status`;
|
||||
VyOS `journalctl -u haproxy` 和只读 stats socket;guest PostgreSQL/K3s journal。
|
||||
日志有保留期限,后续审计应保存经过秘密审查的所需片段。
|
||||
|
||||
### 操作会话
|
||||
|
||||
按维护者指向的 spaces1、spaces3 线索,读取了本地以下实际会话;以会话 ID/标题定位,
|
||||
不把 UI 的位置编号当作长期标识。不复制完整会话或凭据。
|
||||
|
||||
- `01a0d8c1-c4ad-7360-b52e-2a11c34dc13e`,**规划共享 PostgreSQL 数据库**:
|
||||
17:11:46 工具调用 `ansible-playbook pve-storage.yml`;17:20:27 输出显示默认
|
||||
`c-max-rate=102400k`,这只是配置上限,不是已测吞吐;17:25:58 两卷限速成功;
|
||||
17:30–17:31 报告 CT150 恢复;对应 rollout 的关键记录在行 1916、2019、2068 附近。
|
||||
- `01a0d972-e6e5-7432-ad4b-4fd7ca7b3956`,**配置 Alertmanager 通知**:
|
||||
17:13 用户确认测试通知送达;17:20 后观察到 etcd 新故障;17:24:37 用户确认
|
||||
另一路正在调整 etcd;约 17:28–17:30 记录监控覆盖缺口。该会话的监控盘点不等于
|
||||
对 sandbox 集群做过完整事故验收。
|
||||
- `01a0d9a9-7ef0-7992-a313-54668bb3b4e4`,**检查 VyOS 上的 LB 配置**:
|
||||
本次 sandbox 诊断、CT148 离线恢复和最终链路验收。
|
||||
|
||||
本地原记录位于 `/home/panxiao81/.codex/sessions/2026/09/25/`。
|
||||
会话说明只能证明当时的判断;时间线中执行结果以工具回执、PVE 任务和内核日志交叉核对。
|
||||
|
||||
### 相关源码与运行手册
|
||||
|
||||
- etcd rootfs 迁移:`infrastructure/etcd/ansible/move-storage.yml`
|
||||
- PG 数据卷准备:`infrastructure/shared-postgresql/ansible/pve-storage.yml`
|
||||
- 新卷限速任务:`infrastructure/shared-postgresql/ansible/tasks/limit-resync.yml`
|
||||
- etcd 故障恢复记录:`infrastructure/etcd/README.md`
|
||||
- shared PostgreSQL 当前部署边界:`infrastructure/shared-postgresql/README.md`
|
||||
- sandbox 架构与数据库依赖:`infrastructure/sandbox-cluster/README.md`
|
||||
|
||||
上述源码路径相对于 homelab-infra;etcd/shared-postgresql 文件在取证时仍未提交,
|
||||
当前文件已包含事故后的限速补丁,不能倒推事故前已经有同样保护。
|
||||
本报告以 wiki 为唯一维护位置,长期操作流程见[Proxmox 恢复手册](../services/proxmox.md#sandbox-lb-与根文件系统恢复)。
|
||||
源码合并后再补其固定版本链接。
|
||||
|
||||
### 取证过程中的敏感输出问题
|
||||
|
||||
首次 VyOS 查询误认为 `cli-shell-api showConfig` 尾随 `load-balancing` 会限制子树,
|
||||
实际返回完整配置,包含 WireGuard 私钥及登录密码哈希,进入了本会话工具输出。
|
||||
后续已改为设备端提取所需段,并在 `CLAUDE.md` 记录陷阱;未把敏感值写入报告或仓库。
|
||||
既有会话记录并未因此消除,应限制其分享;相关凭据轮换需另行安排,不能称为已处理完毕。
|
||||
Reference in New Issue
Block a user