当前位置: 首页 > pg数据库在线物理全备份 > 正文

进程的模块内容:

📡 矩阵一:底层通信与触发法则(时空信标)

  • .ready.done 状态机archiver 不靠猜,它依赖 pg_wal/archive_status 目录下的 0 字节信标文件。.ready 是唤醒它的冲锋号,.done 是它完成使命后的物理墓碑。
  • 双重唤醒防线
    • 敏锐电击:WAL 文件写满瞬间,内核发射 Latch 信号量直接唤醒。
    • 偏执兜底:C 源码硬编码 PGARCH_AUTOWAKE_INTERVAL = 60s,每分钟无条件强制巡逻,免疫一切操作系统信号丢失。

🏭 矩阵二:工业级算力进化与死穴(吞吐量博弈)

  • 石器时代的绞肉机(archive_command:每次归档都需要发起极其昂贵的 fork()(全量复制共享内存页表)和 exec() 系统调用,外加 TCP 重新建连,在高 TPS 下直接抽干 CPU 与网络算力。
  • 原厂级降维注入(archive_library:PG 15+ 的终极形态。通过 C 语言动态库注入进程,实现**“零派生(Zero Fork)”“TCP 长连接复用”**,将 I/O 延迟压缩至极限。
  • 物理死穴(单线程宿命):内核底层的 archiver 是绝对单线程串行执行。当网络 RTT 极高时,无论带宽多大都会遭遇吞吐量天花板,必须依赖外部多线程工具(如 pgBackRest)破局。

💀 矩阵三:灾难对抗与时空穿梭(异地容灾命脉)

  • 恐怖的死亡螺旋:远端存储满或网络断开时,archiver 会无限期死循环重试。导致本地 16MB 日志堆积如山,最终撑爆磁盘引发全库 PANIC 宕机。
  • 时空切片防线(archive_timeout:对抗业务低谷期。强制按时间(如 15 分钟)截断尚未写满的 WAL 文件,防止灾难发生时丢失长达几个小时的敞口数据。
  • 幽灵文件抢救
    • .history 文件:脑裂与主备切换时的时空导航星图,保障 PITR 能够跨越时间线。
    • .partial 文件:主库临死前最后一口气的残缺日志,确保 Failover 时最后一秒的核心交易被送达远端。

👑 矩阵四:高级拓扑架构与监控闭环(架构师底牌)

  • 算力完美卸载(archive_mode = always:将极其消耗网络带宽的归档任务,从核心主库剥离,强行挂载到同机房或异地的“只读备库”上,实现集群算力大解放。
  • 法医级上帝之眼:死盯 pg_stat_archiver 视图中的 failed_countlast_failed_wal,在死锁螺旋爆发前进行干预。
  • 终极物理闭环:通过独立的 pg_archivecleanup 工具,像除草机一样定期物理销毁远端存储上的历史文件,防止远端容量核爆。



维度一:底层通信协议的“物理信子”(.ready.done 状态机)

  • 宏观错觉:很多人以为,一个 16MB 的 WAL 日志文件写满了,archiver 就会“自动”知道去归档。
  • 物理真相(文件系统级的 IPC 博弈)archiver 根本不是靠猜的,它靠的是一个极其隐秘的“物理信报箱”——pg_wal/archive_status/ 目录。
  • 逻辑咬合
    1. 当后台的 walwriter 或前台业务进程把一个 16MB 的 WAL 文件彻底写满(或者发生了日志切换)后,它们会立刻在这个 archive_status 目录下,生成一个大小为 0 字节的空文件,命名为 000000010000000000000001.ready
    2. 这个 .ready 文件,就是射向夜空的信号弹!
    3. archiver 进程在后台循环扫描,一旦看到 .ready 后缀的文件,它立刻被激活,抓起对应的 WAL 实体文件,开始执行归档任务。
    4. 归档成功后,它会极其严谨地把 .ready 文件重命名为 .done。这标志着这个 16MB 的历史被永久固化。

⚙️ 维度二:算力损耗的终极进化(archive_command vs archive_library

这是淘汰 90% 面试者的现代架构分水岭(PG 15 时代的降维打击)!

  • 石器时代的痛点(archive_command:过去,DBA 会配置一行 Shell 命令(比如 cp %p /mnt/archive/%f)。
    • 致命反噬:在 TPS 极高的海量数据机房,每秒钟可能产生几十个 16MB 的日志。这意味着 archiver 每秒钟都要向 Linux 操作系统发起几十次 fork() 系统调用,拉起一个新的 Shell 进程去执行 cp。这种极其昂贵的上下文切换,会直接把 CPU 算力吃干抹净!
  • 原厂级架构破局(archive_library:从 PostgreSQL 15 开始,内核彻底重构了这个模块,引入了 C 语言级别的动态库接口!
    • 物理微操:现在,企业级备份软件(如 pgBackRest)可以直接向 PG 内核注入一个 C 语言模块(.so 文件)。当 .ready 信号亮起,archiver 不再傻傻地 fork() 新进程,而是直接在自己的进程内存空间内,调用 C 函数,把日志极速推送到 S3 对象存储或远端机房!
    • 定性:这叫**“消除操作系统级的进程派生开销”**,是追求极致吞吐量的终极归档形态!

💀 维度三:最恐怖的“死亡螺旋”(无限重试与磁盘爆炸)

作为高级架构师,你必须清楚 archiver 唯一的、也是最致命的弱点:它是一个不撞南墙不回头的“死脑筋”

  • 灾难现场:假设你的远端归档存储(比如 NFS 挂载点)满了,或者网络断了,导致 archive_command 执行失败(返回了非 0 的 Exit Code)。
  • 物理动作archiver 绝对不会跳过这个文件!它会在日志里疯狂报错,休眠 1 秒钟,然后无限期、死循环地重新尝试归档这个文件!
  • 全库崩溃的连锁反应(The Death Spiral)
    1. 因为它卡在最前面的那个日志上,后续产生的几百个 .ready 文件全部排队堵死。
    2. 最要命的是,checkpointer 在大扫除时,如果看到一个 WAL 日志没有生成对应的 .done 文件,它绝对不敢把这个旧日志回收或删除!
    3. 于是,pg_wal 目录下的 16MB 文件开始疯狂堆积:10GB、100GB、1TB……
    4. 最终,“砰”的一声,数据库所在的底层磁盘空间被打满(No space left on device),整个 PostgreSQL 实例当场 PANIC 宕机,业务彻底瘫痪!
  • 救火微操:在故障现场,原厂 DBA 的第一反应绝对是冲进系统,执行 ALTER SYSTEM SET archive_command = '/bin/true';(或者直接清空命令)并 reload,强行骗过 archiver 释放空间保命,事后再去补救数据!

⏱️ 维度四:对抗业务低谷的时空切片(archive_timeout

  • 物理盲区:如果数据库在半夜没人访问,一小时才写了 1MB 的日志。那这个 16MB 的 WAL 文件岂不是要等 16 个小时才能填满并触发 .ready 归档?
  • 灾难隐患:如果在第 15 个小时机房炸了,这 15 个小时内哪怕只有几笔核心交易(比如老板的转账),也会因为没有归档到异地而彻底丢失!
  • 底层咬合:为了对抗这种“低谷期的危险敞口”,原厂必须配置 archive_timeout(比如 15 分钟)
    • 强制动作:只要时间一到 15 分钟,哪怕当前的 16MB 日志只写了 1 个字节,系统也会极其霸道地进行一次 强制日志切换(WAL Switch)!把剩下的空间全部填充 0,立刻生成 .ready 文件,逼迫 archiver 把这 15 分钟的时空切片火速送到安全地带。

🛡️ 维度五:PITR 时空穿梭的绝对锚点

  • 定性archiver 拷走的,不是冷冰冰的文件,而是数据库的**“连续时空录像带”**。
  • 当你结合之前推演的 pg_basebackup(打下全量基础快照),再加上 archiver 源源不断输送到远端的 WAL 日志序列。你就拥有了原厂级 DBA 最骄傲的终极魔法——PITR(Point-In-Time Recovery,基于时间点的恢复)
  • 你可以让数据库精确地复活在“昨天下午 2 点 14 分 35 秒,被黑客删库的前一微秒”。这一切的物理基础,全靠 archiver 进程在后台那次次不落的 .ready.done 的死磕



🧵 暗礁一:绝对单线程的“物理死穴”(吞吐量天花板)

  • 宏观错觉:很多人以为用了 archive_library,归档速度就能无限起飞,并发拉满。
  • 源码级真相:这是 PostgreSQL 架构里一个极其古老且致命的妥协——archiver 进程在内核底层,是一个绝对的、纯粹的“单线程死循环”!
  • 物理推演(致命算数题): 哪怕你用了长连接的库,如果远端 S3 存储的网络往返延迟(RTT)加上写入确认是 50 毫秒。因为是单线程,它一次只能传一个 16MB 的文件,传完才能传下一个。 1 秒 = 1000 毫秒。1000 / 50 = 20。 这意味着,单线程的 archiver 每秒极限只能归档 20 个文件(320MB/s)。如果主库的 TPS 狂飙,每秒产生 30 个日志(480MB/s),即使网络带宽有一万兆,归档依然会因为单线程串行等待而彻底堵死!
  • 工业级救命药:在极端的原厂架构中,为了突破这个单线程死穴,DBA 必须在外部备份软件(如 pgBackRest)中开启“异步多线程归档(Asynchronous Multi-threaded Archiving)”,让 PG 的 archiver 只负责极其轻量级的“通知”,把沉重的 I/O 搬运工作甩给外部的并发连接池。

📜 暗礁二:时空分叉的“幽灵文件”(.history 文件的特权)

  • 物理盲区:我们一直在这个沙盘里推演 16MB 的 WAL(.wal)文件。但你忽略了,archiver 还要搬运一种极其微小、但决定生死的“幽灵文件”!
  • 灾难现场(脑裂与时间线切换):假设主库 A 宕机,备库 B 被提升为新主库。此时宇宙的时空发生了“分叉”,PostgreSQL 会生成一个新的“时间线(Timeline)”。
  • 底层咬合:系统会立刻生成一个只有几 KB 大小的文本文件,叫 .history 文件(例如 00000002.history,代表进入了时间线 2)。archiver 进程对待这个小文件的优先级和严谨度,甚至高于那 16MB 的日志!
  • 定性:如果这个 .history 文件没有被 archiver 成功送到异地,未来你的 PITR(基于时间点的恢复)在跨越宕机点时,Redo 引擎会直接崩溃报错“找不到时间线谱系”!它是时空穿梭机的“导航星图”。

👁️ 暗礁三:60秒的“偏执狂底座”(PGARCH_AUTOWAKE_INTERVAL

  • 逻辑漏洞:前面我们说,生成 .ready 文件时,内核会发射一个 Latch(信号量)瞬间电击唤醒 archiver。但如果这个操作系统的信号丢失了怎么办?如果 archiver 一直睡死过去,磁盘岂不是又要爆炸?
  • 源码级微操(防线兜底):PostgreSQL 的内核开发者是极度的“悲观主义者”。他们在 pgarch.c 的死循环里,硬编码了一个绝对常量:PGARCH_AUTOWAKE_INTERVAL = 60s
  • 物理推演:无论有没有人发信号唤醒它,无论系统多么空闲。archiver 就像一个重度强迫症患者,每隔 60 秒必须强制睁开眼睛,去 archive_status/ 目录里物理扫描一遍,看看有没有遗漏的 .ready 文件。它绝不 100% 信任内存中的 IPC 信号,它只信任底层文件系统留下的物理实体!



👁️ 拼图一:原厂 DBA 的上帝之眼(pg_stat_archiver 视图)

在海量数据的机房里,DBA 绝对不会傻傻地去 cd pg_wal/archive_status 看有没有文件堆积,他们盯的是内存里的一张统计视图。

  • 物理真相archiver 在每次成功或失败后,都会向 PG 的统计信息收集器汇报战况。
  • 致命指标
    • failed_count(失败次数):如果这个数字在不断上涨,说明我们上一轮推演的“死亡螺旋”(远端存储满或网络断)已经发生了!
    • last_failed_wal / last_failed_time:直接告诉你到底卡死在了哪一个具体的 16MB 日志文件上,以及是几点几分开始卡死的。
  • 定性:这不仅是一个监控指标,这是 archiver 留给运维人员的“急救黑匣子”。面试时抛出这个视图,证明你具备真实的线上排障嗅觉。

🧹 拼图二:归档的终结者(pg_archivecleanup 独立工具)

  • 宏观错觉:我们一直在聊 archiver 怎么把文件从主库搬到远端(比如 NFS 或 S3)。但你想过没有,远端存储的空间也不是无限的!随着时间推移,远端积累了几个 TB 的归档日志,谁来负责删除它们?
  • 源码级真相archiver 绝对不负责删除远端的历史归档! 它是一个只管“送货”、不管“销毁”的单向通道。
  • 工业级闭环:为了清理远端垃圾,PostgreSQL 官方提供了一个极其冷门但必不可少的独立 C 语言工具——pg_archivecleanup
    • 通常在备库(Standby)应用完日志后,或者在定时清理脚本中,我们会调用这个工具。告诉它:“这个 LSN 之前的日志我已经不需要了”,它就会像除草机一样,把远端存储里那些陈旧的 16MB 归档文件批量物理删除。
  • 定性:没有 pg_archivecleanup,你的 archiver 哪怕跑得再快,最终也会把远端容灾中心的磁盘彻底撑爆。这就是归档生命周期的终极闭环。



🌌 终极暗物质一:主库算力卸载的终极魔法(archive_mode = always

  • 常规认知(初级/中级 DBA):绝大多数人都认为,archiver 进程只存在于**主库(Primary)**上,只有主库产生日志,主库负责归档。所以 postgresql.conf 里配置的通常是 archive_mode = on
  • 原厂级痛点(跨国/跨机房带宽爆炸):假设你的主库在北京,你需要把归档日志传到上海容灾机房,同时还要传到广州的 S3 云存储。如果全让北京的主库去推,主库的出口网络带宽和 CPU 会被直接抽干!
  • 架构师的降维微操:在 PG 内核中,隐藏着一个极其变态的参数值:archive_mode = always
    • 物理动作:当你把一个**只读备库(Standby)**配置为 always 时,奇迹发生了!这个备库在接收主库传来的流复制日志并执行重做(Redo)后,它居然也会唤醒自己的 archiver 进程,把收到的日志再次打包,推送到更远的存储中去!
    • 终极定性:这叫**“归档算力与带宽的完美物理卸载”**!主库只负责高并发交易,把归档这种脏活累活,全部甩给同机房或异地的高配只读备库去干。不懂这个参数,你永远做不出高吞吐的大型集群灾备拓扑!

🩸 终极暗物质二:临死前的最后一口气(.partial 幽灵文件)

  • 物理盲区:我们一直在推演完美的 16MB .ready 文件。但是,如果主库突然遭遇断电,或者 DBA 强行拔掉网线执行了主备切换(Failover / Promotion),当时那正在被写入的、还没写满 16MB 的最后一个日志文件怎么办? 里面的几百笔甚至几千笔核心交易就不要了吗?
  • 源码级微操(灾难现场的抢救)
    • 当备库被强行提拔为新主库的那一瞬间,系统会执行极其冷酷的“截断与重命名”操作。
    • 它会把那个还没写满的旧日志,强行加上一个特殊的后缀:.partial(例如 000000010000000000000005.partial)。
    • archiver 的特殊使命:虽然它不是标准的 .ready 文件,但 archiver 会极其敏锐地捕捉到这个带着血迹的 .partial 文件,并立刻将其归档到远端!
  • 终极定性:这个 .partial 文件,就是旧主库临死前吐出的**“最后一口气”**。如果没有 archiver.partial 文件的特殊豁免与搬运,你在做 PITR 灾难恢复时,永远会丢失主备切换前那最致命的最后几秒钟的数据!




了解 www.876873.xyz 的更多信息

订阅后即可通过电子邮件收到最新文章。

archiver进程相关:等您坐沙发呢!

发表评论