bigywater.tech
PostgreSQL · 16

database system was not properly shut down; automatic recovery in progress:PostgreSQL 崩溃恢复要多久,unlogged 表会怎样

“PostgreSQL 日志里 database system was not properly shut down; automatic recovery in progress 是什么意思、崩溃之后数据会丢吗、要恢复多久” 都可以用 kill -9 直接复现。这篇在本机自己起一个 PostgreSQL 16.15,杀后端、杀主进程,看日志、pg_controldata、恢复耗时和 unlogged 表的结局。

0.06 s
kill -9 一个后端后实例自动重启恢复、重新可连接的时间;没提交的事务 0 行,已提交的完好
0.13 → 0.56 s
崩溃前 WAL 从 8 MB 到 230 MB 时,启动到可连接的时间
1000 → 0 行
unlogged 表在崩溃恢复后的行数;普通表的已提交数据仍然在

杀后端

实测 · 本机执行输出
  kill -9 一个后端之后,0.06 s 实例又能连上了;日志:
      LOG:  server process (PID <pid>) was terminated by signal 9: Killed: 9
      DETAIL:  Failed process was running: select pg_backend_pid()
      LOG:  terminating any other active server processes
      LOG:  all server processes terminated; reinitializing
      LOG:  database system was not properly shut down; automatic recovery in progress
      LOG:  redo starts at 0/<lsn>
      LOG:  redo done at 0/<lsn> system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
      LOG:  database system is ready to accept connections
  另一个连接(正在事务里)之后的报错: OperationalError: consuming input failed: server closed the connection unexpectedly
  崩溃前没提交的 insert(id = 5000)还在不在: 0 行;已提交的 1000 行: 1000 行

kill -9 一个后端会让所有连接断开、实例重新初始化并做崩溃恢复,没提交的事务消失。

杀主进程

实测 · 本机执行输出
  崩溃前的 pg_controldata: in production
  postmaster 被杀之后,pg_controldata: in production ;postmaster.pid 还在: True
  pg_ctl start 的输出: waiting for server to start.... done | server started | pg_ctl: another server might be running; trying to start server anyway
      LOG:  database system was not properly shut down; automatic recovery in progress
      LOG:  redo starts at 0/<lsn>
      LOG:  invalid record length at 0/<lsn>: expected at least 24, got 0
      LOG:  redo done at 0/<lsn> system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.00 s
      LOG:  checkpoint starting: end-of-recovery immediate wait
      LOG:  checkpoint complete: wrote 11 buffers (0.1%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.001 s, total=0.001 s; sync files=5, longest=0.001 s,
      LOG:  database system is ready to accept connections
  恢复之后 2500 以内的已提交行数: 1500 (1000 + 500 条是崩溃前提交的)

postmaster 被杀后 pg_controldata 仍是 in production,再启动时做恢复;pg_ctl 会提示 another server might be running。

恢复时间

实测 · 本机执行输出
      崩溃前的 WAL 量        启动到可连接 s       日志里 redo 耗时 s
             8 MB            0.13                0.01
            61 MB            0.26                0.08
           230 MB            0.56                0.36

大致随上次检查点后的 WAL 量线性增长,是检查点间隔的权衡。

unlogged 表

实测 · 本机执行输出
  崩溃前:unlogged 表 1000 行,普通表 id=9999: 1 行
  崩溃恢复后:unlogged 表 0 行,普通表 id=9999: 1 行

不写 WAL,崩溃恢复后被清空。

正常关闭

实测 · 本机执行输出
  fast 关闭之后,pg_controldata: shut down
  再启动用了 0.13 s;日志里 not properly shut down:没有,redo starts:没有

fast 关闭做关闭检查点,再启动不需要 redo。

分步演示

崩溃恢复实测
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / PostgreSQL 16.15(Homebrew);每个实验自己 initdb 一个数据目录,端口 9261 起,只监听 127.0.0.1,不碰本机已有的 5432 上的实例;命令行工具统一用 LC_ALL=C 取英文原文,路径换成 ;计时用 time.perf_counter 或 EXPLAIN ANALYZE 的 Execution Time,数字每次运行会有小幅抖动;实验结束后整个数据目录删除。fsync = on、synchronous_commit = on;checkpoint_timeout = 1h、max_wal_size = 8GB,检查点只在手动执行时发生;只 kill 本实验实例的进程(从 postmaster.pid 取号码);恢复耗时是一次运行的结果
    • 没有验证:操作系统崩溃或断电(kill -9 只是进程崩溃,操作系统缓存里的数据还在,所以没法验证未刷盘数据的丢失);硬件写缓存;备库的崩溃恢复;恢复期间 hot standby 的行为;recovery_prefetch;PostgreSQL 其他大版本的日志措辞
    京ICP备2026067502号-1京公网安备11010502063487号