合 PG启用checksum数据块校验及pg_checksums、pg_verify_checksums命令
Tags: PG其它命令介绍checksumpg_checksumspg_verify_checksums校验和
checksum简介
在计算机系统中,checksum 通常用于校验数据在传输或存取过程中是否发生错误。PostgreSQL从 9.3 开始支持 checksum,以发现数据因磁盘、 I/O 损坏等原因造成的数据异常。
PostgreSQL 从 9.3 开始支持数据页的 checksum,可以在执行 initdb
时指定 -k
或 --data-checksums
参数开启 checksum,但开启 checksum 可能会对系统性能有一定影响,官网描述如下:
Use checksums on data pages to help detect corruption by the I/O system that would otherwise be silent. Enabling checksums may incur a noticeable performance penalty. If set, checksums are calculated for all objects, in all databases. All checksum failures will be reported in the pg_stat_database view.
视图pg_stat_database
记录了校验和数据页失败的页数。
启用 checksum 后,系统会对每个数据页计算 checksum,从存储读取数据时如果检测 checksum 失败,则会发生错误并终止当前正在执行的事务,该功能使得 PostgreSQL 自身拥有了检测 I/O 或硬件错误的能力。
Checksum 引入一个 GUC 参数 ignore_checksum_failure
,该参数若设置为 true
,checksum 校验失败后不会产生错误,而是给客户端发送一个警告。当然,checksum 失败意味着磁盘上的数据已经损坏,忽略此类错误可能导致数据损坏扩散甚至导致系统奔溃,此时宜尽早修复,因此,若开启 checksum,该参数建议设置为 false
,默认为false。
PostgreSQL checksum 行为:
1、开启checksum后,PostgreSQL 从shared buffer把数据write出去,需要计算checksum。
2、开启checksum后,从shared buffer外面(disk, os page cache)读取BLOCK到shared buffer里面,需要计算block的checksum,对比存储在page head里头的checksum是否一致。
3、已经在shared buffer里面的block,变更、读取时并不需要计算checksum。
数据页的 checksum 在从 Buffer pool 刷到存储时才设置,当页面再次读取至 Buffer pool 时进行检测。PostgreSQL 会在页面从存储读入内存时检测其是否可用,调用函数为 PageIsVerified
,该函数不仅会检测正常初始化过的页(non-zero page
),还会检测 全零页(all-zero page)
。
为什么会出现
全零页
呢?
在特定场景下表中可能出现全零页
,比如有进程扩展了一个表,即在该表中添加了一个新页,但在 WAL 日志写入存储之前,进程崩溃了。此时新加的页可能已经在表文件中,下次重启时就会读取到。
对于 non-zero page
,检测其 checksum 是否一致以及 page header 信息是否正确,若 checksum 失败,但 header 信息正确,此时会根据 ignore_checksum_failure
值判断验证是否通过;对于 all-zero page
,如果为全零,则验证通过。
若验证失败,两种处理方式:
若读取数据的模式为
RBM_ZERO_ON_ERROR
且 GUC 参数zero_damaged_pages
为 true,则将该页全部置 0报错,
invalid page
Checksum 使 PostgreSQL 具备检测因硬件故障或传输导致数据不一致的能力,一旦发生异常,通常会报错并终止当前事务,用户可以尽早察觉数据异常并予以恢复。当然,开启 checksum 也会引入一些开销,体现在两个方面:
- 计算数据页的 checksum 会引入一些 CPU 开销,具体开销取决于 checksum 算法的效率
- checkpoint 后,若因更新 Hint Bits 将页面第一次置为
dirty
会写一条记录Full Page Image
的 WAL 日志,以用于恢复因更新 Hint Bits 产生的破碎页。
对于数据可用性要求较高的场景,通常建议将 full_page_writes
和 checksum 都打开,前者用于避免写失败导致的数据缺失,后者用于尽早发现因硬件或传输导致数据不一致的场景,一旦发现,可以利用 full_page_writes
和 checksum 记录在 WAL 日志中的 Full Page Image
进行数据恢复。
查看 checksum
PostgreSQL 10 在 pageinspect
插件中添加了函数 page_checksum()
用来查看 page 的 checksum,当然使用 page_header()
也可以查看 page 的 checksum,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | postgres=# create extension pageinspect; CREATE EXTENSION postgres=# SELECT page_checksum(get_raw_page('pg_class', 0), 0); page_checksum --------------- -18438 (1 row) postgres=# SELECT * FROM page_header(get_raw_page('pg_class', 0)); lsn | checksum | flags | lower | upper | special | pagesize | version | prune_xid -----------+----------+-------+-------+-------+---------+----------+---------+----------- 0/184EA10 | -18438 | 1 | 212 | 5752 | 8192 | 8192 | 4 | 505 (1 row) |
PG12命令之pg_checksums
简介
官网:http://postgres.cn/docs/13/app-pgchecksums.html
对于一些数据可靠性要求很高的场景,例如金融领域,建议打开数据块的checksum校验功能。