data_checksums 介绍
由于存储介质故障,突然断电等问题,导致数据块中存储的信息丢失,或由于没来得及写入完成导致的块断裂,坏块通常会带来数据损坏甚至数据丢失的风险,为了保证数据的完整性,通常需要对数据块进行校验和。
data_checksums 如何工作:
- checksum 校验发生在数据页落盘之前和进入 sharedbuffer 之前。
- 当将页面从缓冲区缓存写入到操作系统页面缓存时,就会计算 checksum 值并写入到数据页中。
- 每次读取该块时,checksum 值就会重新计算,并与所存储的 checksum 值进行比较,这可以检验数据是否损坏。
如何开启data_checksums
查看是否有启用
select * from pg_catalog.pg_settings wherenamelike'%data_checksums%';
或者
[postgres@192 root]$ pg_controldata |grep checksum
data_checksum 默认是关闭,当你调⽤initdb程序时, 添加‑‑data‑checksums标志(如果你更喜欢短参数,则添加‑k),你崭新的Postgres集群将启⽤数据校验和。如果一开始初始化没有指定,后续也可以通过 po_checksum 进行启用。
Postgres的第12 版引⼊了⼀个新的内置程序pg_checksum,它可以在现有的⽆校验和数据库上启⽤校验和。
[postgres@192 root]$ pg_checksums --help pg_checksums enables, disables, or verifies data checksums in a PostgreSQL database cluster. Usage: pg_checksums [OPTION]... [DATADIR] Options: [-D, --pgdata=]DATADIR data directory -c, --check check data checksums (default) -d, --disable disable data checksums -e, --enable enable data checksums -f, --filenode=FILENODE check only relation with specified filenode -N, --no-sync do not wait for changes to be written safely to disk -P, --progress show progress information --sync-method=METHOD set method for syncing files to disk -v, --verbose output verbose messages -V, --version output version information, then exit -?, --help show this help, then exit If no data directory (DATADIR) is specified, the environment variable PGDATA is used. Report bugs to <pgsql-bugs@lists.postgresql.org>. PostgreSQL home page: <https://www.postgresql.org/> data_checksums启用 pg_checksums -D $PGDATA --enable --progress #启用校验和时,所有数据块都能产生校验和信息并写入到数据库 data_checksums禁用 pg_checksums -D $PGDATA --disable --progress #禁用校验和只会更新pg_control文件,读写数据块操作时将不进行校验 不管是启用或者禁用,都要在数据库关闭后进行注入式攻击-嫁接式数据块
data_checksums 在未启用的环境下容易被非正常 insert 注入,下面我们来做个实验看一下:
#新建两张新表,表结构要一致 postgres=# create table t1 (a int); CREATE TABLE postgres=# insert into t1 values(1); INSERT 0 1 postgres=# create table t2 (a int); CREATE TABLE postgres=# insert into t2 values(1111); INSERT 0 1 #查看表的位置 postgres=# select pg_relation_filepath('t1'); pg_relation_filepath ---------------------- base/5/16426 (1 row) postgres=# select pg_relation_filepath('t2'); pg_relation_filepath ---------------------- base/5/16429 (1 row) [root@192 5]# dd bs=8192 count=1 seek=1 of=16426 if=16429 1+0 records in 1+0 records out 8192 bytes (8.2 kB, 8.0 KiB) copied, 0.000207962 s, 39.4 MB/s [postgres@192 root]$ pg_ctl stop [postgres@192 root]$ pg_ctl start postgres=# select * from t1; a ------ 1 1111 (2 rows)如果这时候开启 data_checksum,会发现一条报错信息,因为有一个块是我们非法插入的。
pg_checksums: error: could not read block 1 in file "/data/pgsql/data/base/5/16429": read 1 of 8192
如何读取坏块里的数据
data_checksums 启用环境下操作。
忽略 checksum 报错,读出坏块中的数据
set ignore_checksum_failure=on;
注意:ignore_checksum_failure 该参数仅在开启 checksum 下生效,作用就是忽略 checksum 的报错,读出坏块中的数据。但是假如 page header 错误,要么就读不出来,事务依旧会终止
set zero_damaged_pages=on;
zero_damaged_pages 这个参数会导致数据块会在内存中将损坏的 page 都置为空,然后获取剩下的结果,即使 page_header 损坏,执行事务也不会退出,只会报 warning。