Files
homelab-wiki/incidents/2026-09-25-drbd-quorum-sandbox.md
2026-09-25 18:09:49 +00:00

229 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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` 记录陷阱;未把敏感值写入报告或仓库。
既有会话记录并未因此消除,应限制其分享;相关凭据轮换需另行安排,不能称为已处理完毕。