openGauss postmaster退出流程

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)


二、三种关机模式的入口

  1. 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)(还没起来)

  • 否则继续后续流程

  1. 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)

  • 否则继续后续流程

  1. 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)

相关推荐
神一样的老师几秒前
WS63 访问 HTTPS 握手失败(-0x7780)根治
数据库·网络协议·https
Patrick在香港21 分钟前
时间戳凭空早了 8 小时:datetime.utcnow() 弃用实测与漂移复盘
数据库·python·标准库·datetime·时区·弃用
李兆龙的博客8 小时前
问津集 #26:Lakebase——Postgres 的版本化页面存储、数据库分支与计算弹性
数据库
倔强的石头_10 小时前
聊聊金仓KFS:一款把数据同步软件做扎实的产品
数据库
闲云野鹤在人间11 小时前
MySQL|从理论、安装、备份到主从复制、MHA高可用详解
linux·运维·数据库·mysql·云计算
禾小西11 小时前
Redis:从两大维度和三大主线建立知识体系
数据库·redis·缓存
禾小西11 小时前
Redis 数据结构:快速的 Redis 有哪些慢操作?
数据结构·数据库·redis
数据库小学妹12 小时前
数据共享交换平台选型:交换方式对比与避坑指南
数据库·信创·数据同步·数据交换平台·政务数据共享·数据共享交换平台·数据库底座
loong_XL13 小时前
决策模型做内容安全检测:从踩坑到上线
数据库·安全·jev·决策模型
这个DBA有点耶13 小时前
数据库双轨并行实战:全量并行策略、增量延迟控制、双向回切与一致性校验
数据库·架构·dba