Postmaster 关机退出流程与状态变化
一、全局状态变量
volatile PMState pmState = PM_INIT; // 当前 PM 状态
volatile int Shutdown = NoShutdown; // 关机请求级别
Shutdown 级别(由信号设置):
-
NoShutdown = 0
-
SmartShutdown = 1(SIGTERM,等事务结束)
-
FastShutdown = 2(SIGINT,立即回滚事务)
-
ImmediateShutdown = 3(SIGQUIT,直接退出)
PMState 状态机序列(正常关机):
PM_RUN → PM_WAIT_BACKENDS → PM_SHUTDOWN → PM_SHUTDOWN_2 → PM_WAIT_DEAD_END → PM_NO_CHILDREN → ExitPostmaster(0)
二、三种关机模式的入口
- Smart Shutdown (SIGTERM) --- 仅主库在 standby mode 时
postmaster.cpp:6488-6505
-
设置 g_instance.status = SmartShutdown
-
调用 pgaudit_system_stop_ok(SmartShutdown)
-
如果 pmState == PM_STARTUP || PM_INIT → 立即 ExitPostmaster(0)(还没起来)
-
否则继续后续流程
- Fast Shutdown (SIGINT / non-standby SIGTERM)
postmaster.cpp:6506-6521
-
设置 g_instance.status = FastShutdown
-
调用 pgaudit_system_stop_ok(FastShutdown)
-
如果 pmState == PM_STARTUP || PM_INIT → 立即 ExitPostmaster(0)
-
否则继续后续流程
- Immediate Shutdown (SIGQUIT)
postmaster.cpp:6789-6809
-
设置 g_instance.status = ImmediateShutdown
-
调用 KillGraceThreads() → 发送 SIGQUIT 给 AlarmCheckerPID
-
调用 ExitPostmaster(0) --- 直接退出,不等待任何子进程
三、Fast/Smart Shutdown 详细流程(主线)
收到信号后进入 pmdie() 的主流程(postmaster.cpp:6527-6787):
阶段 1:终止各类进程
A. 如果在 PM_RECOVERY 状态:
// postmaster.cpp:6733-6747
if (ENABLE_THREAD_POOL) g_threadPoolControler->ShutDownThreads();
if (pmState == PM_RECOVERY) {
pmState = PM_WAIT_BACKENDS; // 直接进入等待
}
B. 如果在 PM_RUN / PM_HOT_STANDBY / PM_WAIT_BACKUP / PM_WAIT_READONLY / PM_WAIT_BACKENDS 状态:
// postmaster.cpp:6748-6777
ereport(LOG, (errmsg("aborting any active transactions")));
// 1. 关闭线程池
if (ENABLE_THREAD_POOL) {
g_threadPoolControler->CloseAllSessions();
g_threadPoolControler->ShutDownScheduler(true, true);
g_threadPoolControler->ShutDownThreads();
}
// 2. 发送 SIGTERM 给所有普通后端和 autovacuum worker
SignalSomeChildren(SIGTERM, BACKEND_TYPE_NORMAL | BACKEND_TYPE_AUTOVAC);
// 3. 关闭所有 background worker
ShutdownAllBgWorker();
// 4. 发送 SIGTERM 给特殊子进程
signal_child(AutoVacPID, SIGTERM); // autovac launcher
signal_child(PgJobSchdPID, SIGTERM); // job scheduler
signal_child(WalWriterPID, SIGTERM); // WAL writer
signal_child(WalWriterAuxiliaryPID, SIGTERM);
pmState = PM_WAIT_BACKENDS;
C. 发送信号后的关键逻辑:
PostmasterStateMachine(); // 尝试推进状态机
四、PostmasterStateMachine 状态机推进
核心函数:PostmasterStateMachine() --- postmaster.cpp:9197
状态 1: PM_WAIT_BACKENDS → 等所有后端退出
// 条件检查:所有子进程都退出了
if (CountChildren(BACKEND_TYPE_NORMAL | BACKEND_TYPE_AUTOVAC) == 0 &&
StartupPID == 0 && TwoPhaseCleanerPID == 0 && FaultMonitorPID == 0 &&
WalReceiverPID == 0 && WalRcvWriterPID == 0 && DataReceiverPID == 0 &&
DataRcvWriterPID == 0 && BgWriterPID == 0 && WalWriterPID == 0 &&
WalWriterAuxiliaryPID == 0 && AutoVacPID == 0 && SpBgWriterPID == 0 &&
WLMCollectPID == 0 && WLMMonitorPID == 0 && WLMArbiterPID == 0 &&
CPMonitorPID == 0 && PgJobSchdPID == 0 && CBMWriterPID == 0 &&
TxnSnapCapturerPID == 0 && RbCleanrPID == 0 && SnapshotPID == 0 &&
AshPID == 0 && CsnminSyncPID == 0 && StackPerfPID == 0 &&
CfsShrinkerPID == 0 && rackMemCleanerPID == 0 &&
BarrierCreatorPID == 0 && PageRepairPID == 0 && BarrierPreParsePID == 0 &&
SqlLimitPID == 0 && UndoLauncherPID == 0 && UndoRecyclerPID == 0 &&
GlobalStatsPID == 0 && IsAllPageWorkerExit() && IsAllBuildSenderExit())
当条件满足且 !g_instance.fatal_error:
// postmaster.cpp:9273-9347
// 1. 启动 checkpointer(如果没运行)
if (CheckpointerPID == 0) initialize_util_thread(CHECKPOINT_THREAD);
// 2. 停止 page writer
ckpt_cxt_ctl->page_writer_can_exit = false;
for (各 PageWriterPID) signal_child(SIGTERM);
WaitUntilPagewriterReceiveSigterm();
// 3. 等待 logical walsender 进入 stopping 状态
SigtermWalsenderToStoppingState();
WaitUntilWalsenderReceiveSigterm();
// 4. 通知 checkpointer 做 shutdown checkpoint
signal_child(CheckpointerPID, SIGUSR2);
pmState = PM_SHUTDOWN; // ← 关键状态跳转
状态 2: PM_SHUTDOWN → 等 Checkpointer 退出
在 reaper() 中(postmaster.cpp:7882-7914):
if (pid == CheckpointerPID && EXIT_STATUS_0(exitstatus) && pmState == PM_SHUTDOWN) {
CheckpointerPID = 0;
// 如果有 shared storage xlog copy thread
if (sharedStorageXlogCopyThreadPID != 0)
signal_child(sharedStorageXlogCopyThreadPID, SIGTERM);
// ...
}
Checkpointer 收到 SIGUSR2 后执行 shutdown checkpoint:
-
调用 CreateRestartPoint(CHECKPOINT_IS_SHUTDOWN | CHECKPOINT_IMMEDIATE)
-
刷脏页到磁盘
-
写入 checkpoint record 到 WAL
-
退出(exit 0)
状态 3: PM_SHUTDOWN_2 → 等 archiver 和 walsender 退出
// postmaster.cpp:9358-9378
if (pmState == PM_SHUTDOWN_2) {
if (PgArchPID == 0 && CountChildren(BACKEND_TYPE_ALL) == 0 &&
WalReceiverPID == 0 && WalRcvWriterPID == 0 &&
DataReceiverPID == 0 && DataRcvWriterPID == 0 &&
ObsArchAllShutDown() && HeartbeatPID == 0 &&
sharedStorageXlogCopyThreadPID == 0) {
pmState = PM_WAIT_DEAD_END;
}
}
PM_SHUTDOWN_2 的触发(checkpointer 退出后):
// 在 reaper 中,checkpointer 退出后会进一步处理
pmState = PM_SHUTDOWN_2;
// 发送 SIGTERM 给 archiver 和 walsender
signal_child(PgArchPID, SIGTERM);
signal_child(WalReceiverPID, SIGUSR2); // 通知 walsender 发送剩余 WAL
状态 4: PM_WAIT_DEAD_END → 等 dead_end 子进程退出
// postmaster.cpp:9380-9404
if (pmState == PM_WAIT_DEAD_END) {
if (DLGetHead(backend_list) == NULL && PgArchPID == 0 &&
AuditAllShutDown() && ckpt_all_flush_buffer_thread_exit() &&
ObsArchAllShutDown() && !SS_PERFORMING_SWITCHOVER) {
AsssertAllChildThreadExit();
pmState = PM_NO_CHILDREN;
}
}
状态 5: PM_NO_CHILDREN → ExitPostmaster
// postmaster.cpp:9418-9438
if (g_instance.status > NoShutdown && pmState == PM_NO_CHILDREN) {
if (g_instance.fatal_error) {
ereport(LOG, (errmsg("abnormal database system shutdown")));
ExitPostmaster(1);
} else {
if (t_thrd.postmaster_cxt.ReachedNormalRunning)
CancelBackup(); // 取消 exclusive backup 模式
ExitPostmaster(0); // ← 正常退出
}
}
五、各子进程退出行为
| 进程 | 接收信号 | 退出行为 |
|---|---|---|
| Backend (普通) | SIGTERM | 回滚活跃事务,优雅退出 |
| Autovacuum Worker | SIGTERM | 停止 vacuume,优雅退出 |
| AutoVac Launcher | SIGTERM | 停止 launcher,退出 |
| WalWriter | SIGTERM | 完成当前 WAL 写入,退出 |
| BgWriter | SIGTERM | 完成刷脏,退出 |
| Checkpointer | SIGUSR2 (shutdown) | 执行 shutdown checkpoint,退出 |
| WalSender | SIGUSR2 | 发送剩余 WAL,等待同步,退出 |
| PgArch (归档) | SIGTERM | 完成当前归档,退出 |
| SysLogger | SIGUSR1 (flush) | 刷新日志缓冲,退出 |
| WalReceiver | SIGTERM | 断开复制连接,退出 |
| DataReceiver | SIGTERM | 断开数据接收,退出 |
| PageWriter | SIGTERM | 完成页面写入,退出 |
六、Shutdown 级别对比
| 特性 | Smart (SIGTERM) | Fast (SIGINT) | Immediate (SIGQUIT) |
|---|---|---|---|
| 等事务结束 | ✅ | ❌ | ❌ |
| 写 shutdown checkpoint | ✅ | ✅ | ❌ |
| 等子进程退出 | ✅ | ✅ | ❌ |
| 下次启动需 recovery | 否 | 可能(快关可能丢未刷数据) | 是 |
| 数据一致性 | 最佳 | 好 | 可能不一致 |
| 适用场景 | 计划停机 | 紧急停止 | 卡死/崩溃恢复 |
七、流程图总结
收到信号
│
├─ SIGQUIT → ImmediateShutdown → KillGraceThreads → ExitPostmaster(0) 【直接退出】
│
├─ SIGTERM (standby) → SmartShutdown
└─ SIGTERM/SIGINT (其他) → FastShutdown
│
├─ PM_STARTUP/PM_INIT → ExitPostmaster(0) 【还没起来,直接退】
│
└─ PM_RUN/PM_RECOVERY/PM_HOT_STANDBY
│
├─ 关闭 ThreadPool (CloseAllSessions + ShutDownThreads)
├─ SIGTERM → 所有 Backend + Autovac
├─ ShutdownAllBgWorker()
├─ SIGTERM → AutoVac, PgJobSchd, WalWriter
│
▼
PM_WAIT_BACKENDS
│
│ 等所有后端退出 (CountChildren == 0)
▼
启动/唤醒 Checkpointer
SIGTERM → PageWriter
SIGTERM → Logical WalSender (等进入 stopping)
SIGUSR2 → Checkpointer (做 shutdown checkpoint)
│
▼
PM_SHUTDOWN
│
│ 等 Checkpointer 退出 (exit 0)
▼
PM_SHUTDOWN_2
│
│ 发 SIGTERM → Archiver, Walsender
│ 等所有非 syslogger 子进程退出
▼
PM_WAIT_DEAD_END
│
│ 等 backend_list 为空 + Archiver 退出
▼
PM_NO_CHILDREN
│
▼
ExitPostmaster(0) ← 正常退出
ExitPostmaster(1) ← 异常退出 (fatal_error)