跳至内容
35.1 现场保护与操作边界

35.1 现场保护与操作边界

数据损坏现场与普通性能事故不同:每一次 checkpoint、vacuum、restart、reindex、文件 删除甚至查询,都可能改变证据或覆盖本来还能读取的内容。第一目标是建立一个不再 变化的证据点,不是赶紧让告警变绿。

35.1.1 停写、只读、快照、克隆与证据哈希

先冻结新增变量

按影响面与 authority 选择:

stop application writes at admission
drain write service routes
revoke/disable affected writer credentials when authorized
place exact application in maintenance/read-only mode
fence a suspect instance from accepted database authority
stop PostgreSQL cleanly when evidence and recovery design require it

“只读”要区分三层:

能证明什么不能证明什么
应用只读正常业务不发写请求运维、直连、后台任务不会写
数据库 transaction read-only该 session 不执行普通写所有 session/后台都停止
存储 snapshot/read-only mount捕获某个块状态snapshot 一定应用一致、源存储健康

不要把 promotion 当作“自动停写旧主”。若故障域是共享存储或坏内存,健康副本也可能 已接收同一损坏;若旧主没有 fence,切换还会增加两个可写历史的风险。

快照有一致性等级

crash-consistent
  相当于某一瞬间掉电,必须有完整 PGDATA + tablespace + WAL,启动时 recovery

application-consistent
  数据库与外部系统的业务 checkpoint/ledger 一致

clean-stopped
  PostgreSQL clean shutdown 后复制,适合离线工具与确定性实验

文件系统/storage snapshot 只有在覆盖所有 tablespace、WAL 路径与必要元数据,且写入 顺序语义可靠时,才可作为 crash-consistent PostgreSQL 副本。只复制 base/ 不是 PGDATA snapshot。

本章正式实验使用 clean-stopped known-good snapshot。生产未必有条件 clean stop; 那时应保留 crash-consistent snapshot,并在克隆上让 PostgreSQL recovery。

原始、来源、操作副本分开

original evidence
  发现异常时的最早可保存状态;只读、封存

known-good source
  经备份/副本/快照验证的恢复来源;只读、封存

working copy A/B/C
  每项假设从同一 source/evidence 分叉,可丢弃

不要让“原始损坏副本”与“可信恢复源”共用一个标签 backup。前者用于解释发生了什么, 后者用于恢复正确状态。

哈希证明什么

对封存文件树记录:

algorithm: SHA-256
relative path
size
digest
capture UTC
source device/snapshot identity
collector/tool version

哈希相同只证明两次计算之间字节相同,不证明第一次采集时就正确,也不证明未遗漏 tablespace、WAL 或外部对象。manifest 本身也应签名/受控保存,且不能把口令、密钥、 原始业务数据无界导出到普通 evidence 目录。

35.1.2 记录硬件、内核、日志、版本和最近变更

建立同一 UTC 时间线

至少记录:

identity:
  cluster_system_identifier: ...
  timeline_and_lsn: ...
  instance_host_storage_ids: ...
software:
  postgres_server_and_binary: ...
  extensions: ...
  os_kernel_libc_icu: ...
  filesystem_storage_firmware: ...
configuration:
  data_checksums: ...
  full_page_writes: ...
  locale_collation_versions: ...
  tablespaces_and_wal_paths: ...
events:
  first_user_symptom: ...
  first_postgres_error: ...
  kernel_storage_memory_events: ...
  deploy_upgrade_failover_backup: ...
  power_or_hypervisor_event: ...

日志要保留原时区、sequence/journal cursor、rotation 边界与原始文件哈希。摘抄一行 invalid page in block 7 会丢掉前后的 I/O error、backend identity 和 relation context。

版本是故障证据

以下差异都可能改变解释:

  • PostgreSQL major/minor 与启动该 PGDATA 的 binary;
  • extension shared library 与 SQL extension version;
  • libc/ICU/tzdata;
  • filesystem/kernel/storage firmware;
  • primary 与 standby 的 OS/collation provider;
  • backup/restore 工具和 repository format。

不要用“应该都是 PG18”代替实际 server_version_num、package build 和 binary hash。 同 major 的不同操作系统镜像也可能带不同 ICU/libc。

最近变更不等于根因

变更与首个症状相邻,只是候选因果:

change:
  at: ...
  scope: ...
  expected_effect: ...
supports:
  - exact evidence
contradicts:
  - exact evidence
experiment_on_clone:
  - falsifiable check

硬盘 error 同时出现在升级后,不应因为“刚升级”就忽略设备证据;反之硬件告警也可能 是读取已存在坏页时才触发。

35.1.3 不在唯一副本上反复试错

每次尝试都会消耗选择权

start/recovery        may replay WAL and update control state
SELECT                may set hint bits or expose more damaged pages
VACUUM                may remove versions and update visibility maps
REINDEX               replaces derived evidence
pg_checksums --enable rewrites relation blocks in place
zero_damaged_pages    discards all tuples on a page in memory
pg_resetwal           invents WAL/control continuity

因此工作树应是:

evidence E0 (immutable)
  ├─ clone H1: test hardware/filesystem interpretation
  ├─ clone P1: PostgreSQL structural checks
  ├─ clone X1: best-effort logical extraction
  └─ clone R1: candidate recovery

H1 失败后重建 H2,不在 H1 上连续叠加参数。每个 clone 保存输入 hash、动作顺序、输出、 退出状态与结论。

“只有一份”时怎么办

若无法制作 snapshot/clone:

  1. 停止非必要写入和自动恢复;
  2. 记录为什么不能复制(空间、设备状态、加密、访问权);
  3. 评估块级镜像/专业数据恢复而非数据库内试错;
  4. 明确每个读取会否加剧介质故障;
  5. 升级事故级别和专业支持;
  6. 由数据 owner 明确接受任何不可逆动作。

时间压力不增加数据副本。越接近唯一来源,越应减少实验。

35.1.4 绝不手工删除 pg_wal 或原始损坏文件

不要用文件系统动作伪装修复

pg_wal、relation segment、visibility/free-space map、control file 与 tablespace symlink 共同构成 PostgreSQL 状态。手工删除看似坏掉或“旧”的文件:

  • 不更新 catalog/control/WAL recovery 语义;
  • 可能把局部损坏扩大为数据库无法启动;
  • 破坏 replica/PITR/backup 所需 lineage;
  • 覆盖或消灭故障根因证据;
  • 让后续专业工具无法比较原始字节。

即使某个损坏 index 最终可重建,也先保存其 identity、size、hash、错误与依赖关系, 再在 working copy 或受控生产变更中用 PostgreSQL DDL 重建;不要直接 rm index relation file。

自动化也会改现场

临时隔离后检查并暂停可能的自动动作:

Patroni restart/reinit/failover
systemd restart policy
Kubernetes liveness restart
filesystem repair/fsck
cloud auto-replace
backup retention/prune
logrotate and core cleanup
autovacuum/maintenance jobs
monitoring remediation

不是所有自动化都要停,而是必须知道哪些会写现场,并由事故指挥统一决定。

现场保护完成定义

accepted writer stopped or isolated
original evidence identity and hash recorded
known-good recovery candidates named
at least one working copy available, or copy blocker escalated
automatic mutators inventoried
time/version/hardware/change evidence preserved
destructive actions and owners explicitly gated

完成这些才进入下一节的分类。


返回本章目录 · 下一节:先分类再抢救 · 查看全书目录 · 查看索引中心

最后更新于