进程的模块内容:
📡 矩阵一:底层通信与触发法则(时空信标)
.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_count与last_failed_wal,在死锁螺旋爆发前进行干预。 - 终极物理闭环:通过独立的
pg_archivecleanup工具,像除草机一样定期物理销毁远端存储上的历史文件,防止远端容量核爆。
维度一:底层通信协议的“物理信子”(.ready 与 .done 状态机)
- 宏观错觉:很多人以为,一个 16MB 的 WAL 日志文件写满了,
archiver就会“自动”知道去归档。 - 物理真相(文件系统级的 IPC 博弈):
archiver根本不是靠猜的,它靠的是一个极其隐秘的“物理信报箱”——pg_wal/archive_status/目录。 - 逻辑咬合:
- 当后台的
walwriter或前台业务进程把一个 16MB 的 WAL 文件彻底写满(或者发生了日志切换)后,它们会立刻在这个archive_status目录下,生成一个大小为 0 字节的空文件,命名为000000010000000000000001.ready。 - 这个
.ready文件,就是射向夜空的信号弹! archiver进程在后台循环扫描,一旦看到.ready后缀的文件,它立刻被激活,抓起对应的 WAL 实体文件,开始执行归档任务。- 归档成功后,它会极其严谨地把
.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 算力吃干抹净!
- 致命反噬:在 TPS 极高的海量数据机房,每秒钟可能产生几十个 16MB 的日志。这意味着
- 原厂级架构破局(
archive_library):从 PostgreSQL 15 开始,内核彻底重构了这个模块,引入了 C 语言级别的动态库接口!- 物理微操:现在,企业级备份软件(如 pgBackRest)可以直接向 PG 内核注入一个 C 语言模块(
.so文件)。当.ready信号亮起,archiver不再傻傻地fork()新进程,而是直接在自己的进程内存空间内,调用 C 函数,把日志极速推送到 S3 对象存储或远端机房! - 定性:这叫**“消除操作系统级的进程派生开销”**,是追求极致吞吐量的终极归档形态!
- 物理微操:现在,企业级备份软件(如 pgBackRest)可以直接向 PG 内核注入一个 C 语言模块(
💀 维度三:最恐怖的“死亡螺旋”(无限重试与磁盘爆炸)
作为高级架构师,你必须清楚 archiver 唯一的、也是最致命的弱点:它是一个不撞南墙不回头的“死脑筋”。
- 灾难现场:假设你的远端归档存储(比如 NFS 挂载点)满了,或者网络断了,导致
archive_command执行失败(返回了非 0 的 Exit Code)。 - 物理动作:
archiver绝对不会跳过这个文件!它会在日志里疯狂报错,休眠 1 秒钟,然后无限期、死循环地重新尝试归档这个文件! - 全库崩溃的连锁反应(The Death Spiral):
- 因为它卡在最前面的那个日志上,后续产生的几百个
.ready文件全部排队堵死。 - 最要命的是,
checkpointer在大扫除时,如果看到一个 WAL 日志没有生成对应的.done文件,它绝对不敢把这个旧日志回收或删除! - 于是,
pg_wal目录下的 16MB 文件开始疯狂堆积:10GB、100GB、1TB…… - 最终,“砰”的一声,数据库所在的底层磁盘空间被打满(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 分钟的时空切片火速送到安全地带。
- 强制动作:只要时间一到 15 分钟,哪怕当前的 16MB 日志只写了 1 个字节,系统也会极其霸道地进行一次 强制日志切换(WAL Switch)!把剩下的空间全部填充 0,立刻生成
🛡️ 维度五: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进程,把收到的日志再次打包,推送到更远的存储中去! - 终极定性:这叫**“归档算力与带宽的完美物理卸载”**!主库只负责高并发交易,把归档这种脏活累活,全部甩给同机房或异地的高配只读备库去干。不懂这个参数,你永远做不出高吞吐的大型集群灾备拓扑!
- 物理动作:当你把一个**只读备库(Standby)**配置为
🩸 终极暗物质二:临死前的最后一口气(.partial 幽灵文件)
- 物理盲区:我们一直在推演完美的 16MB
.ready文件。但是,如果主库突然遭遇断电,或者 DBA 强行拔掉网线执行了主备切换(Failover / Promotion),当时那正在被写入的、还没写满 16MB 的最后一个日志文件怎么办? 里面的几百笔甚至几千笔核心交易就不要了吗? - 源码级微操(灾难现场的抢救):
- 当备库被强行提拔为新主库的那一瞬间,系统会执行极其冷酷的“截断与重命名”操作。
- 它会把那个还没写满的旧日志,强行加上一个特殊的后缀:
.partial(例如000000010000000000000005.partial)。 archiver的特殊使命:虽然它不是标准的.ready文件,但archiver会极其敏锐地捕捉到这个带着血迹的.partial文件,并立刻将其归档到远端!
- 终极定性:这个
.partial文件,就是旧主库临死前吐出的**“最后一口气”**。如果没有archiver对.partial文件的特殊豁免与搬运,你在做 PITR 灾难恢复时,永远会丢失主备切换前那最致命的最后几秒钟的数据!
了解 www.876873.xyz 的更多信息
订阅后即可通过电子邮件收到最新文章。
archiver进程相关:等您坐沙发呢!