崩溃恢复场景: 用例
下面我们在 PostgreSQL 的数据库中,创建一个表,插入一些数据。
CREATE TABLE t (id integer, name text);
INSERT INTO t (id, name)
SELECT i, repeat('Pg', 32)
FROM generate_series(1, 1000000) AS s(i);
下面我们启动一个事务块,创建一个空表t1
,复制表t
创建一个新表t_copy
,并查看下表文件的存储路径。
BEGIN;
CREATE TABLE t1 ();
CREATE TABLE t_copy AS TABLE t;
SELECT pg_relation_filepath(name) AS path
FROM (VALUES ('t1'), ('t_copy')) AS t (name);
path
--------------
base/5/16389
base/5/16392
让我们立即停止数据库,模拟数据库异常宕机的故障,再重新启动数据库服务:
$ pg_ctl stop --mode=immediate
$ pg_ctl start
数据库重新启动后,手动触发一次检查点:
CHECKPOINT;
检查重启前事务块中新增的表文件:
$ ls -lh base/5/{16389,16392}
-rw------- 1 postgres postgres 0 Aug 18 17:43 base/5/16389
-rw------- 1 postgres postgres 97M Aug 18 17:44 base/5/16392
崩溃恢复场景: 内部原理
下面是我们在 PostgreSQL 的事务中创建表文件时,崩溃恢复后出现表文件残留问题的内部原因:
- 1. PostgreSQL 在事务运行的过程中,会在会话内存中记录创建的表文件。
- 2. 当事务发生异常或者执行回滚操作时,会即时地清除这些表文件。
- 3. 当事务异常中断,如:磁盘不足引发的 PANIC 错误,系统发出的 OOM 内存不足信号,或者发生软件错误的扩展插件,系统停电导致的服务器崩溃时,会话内存中记录的新增表文件会丢失,出现表文件残留的问题。
Redrock Postgres 的解决方案
Redrock Postgres 在创建表文件时,会记录撤消日志,当正在连接的会话因为某些原因被中止后,数据库重新启动后会检查这些异常中止的事务。数据库会回滚这些异常中止的事务,根据记录的撤消日志清理残留的表文件。
下面我们在 Redrock Postgres 的数据库中,创建和上面相同的表,并插入同样的数据。
CREATE TABLE t (id integer, name text);
INSERT INTO t (id, name)
SELECT i, repeat('Pg', 32)
FROM generate_series(1, 1000000) AS s(i);
下面我们启动一个事务块,创建一个空表t1
,复制表t
创建一个新表t_copy
,并查看下表文件的存储路径。
BEGIN;
CREATE TABLE t1 ();
CREATE TABLE t_copy AS TABLE t;
SELECT pg_relation_filepath(name) AS path
FROM (VALUES ('t1'), ('t_copy')) AS t (name);
path
--------------
base/5/16389
base/5/16392
让我们立即停止数据库,模拟数据库异常宕机的故障,再重新启动数据库服务:
$ pg_ctl stop --mode=immediate
$ pg_ctl start
数据库重新启动后,手动触发一次检查点:
CHECKPOINT;
事务回滚的时候不会立即清理残留的表文件,表文件的实际清理操作是在检查点的过程中完成的。
检查重启前事务块中新增的表文件:
$ ls -lh base/5/{16389,16392}
ls: cannot access 'base/5/16389': No such file or directory
ls: cannot access 'base/5/16392': No such file or directory
数据库重新启动后,回滚了异常中止的事务,根据事务记录的撤消日志清理了残留的表文件。
转自:https://mp.weixin.qq.com/s/98DnaCDJPcjFTS2JpxlRYg
该文章在 2025/8/19 10:21:13 编辑过