首页 » PostgreSQL » PostgreSQL无效页面和校验(Checksum)和验证失败(Verification Failed)

PostgreSQL无效页面和校验(Checksum)和验证失败(Verification Failed)

前几天分享了oracle lost write detection, 后来想找找postgresql有没有相同技术,结果没有找到,但是对于对于PostgreSQL中无效页面(Invalid Page In Block)是有发现机制的, PostgreSQL主要在进出buffer cache的过程中维护页面有效性,PostgreSQL在数据库和操作系统(固件,磁盘,网络,远程存储)之间有强大的”边界”。


假设存在物理内存故障或是其它原因产生无效page,并且ECC(Error Checking and Correcting)奇偶校验无法以某种方式检测到它。这意味着服务器上的少量物理内存现在有不正确的数据,并且该内存中的正确数据也丢失了。

1, 如果不正常的数据在 kernel page cache,那么当PostgreSQL尝试将page复制到其buffer cache时,它将(如果可能)检测到错误,请拒绝加载的8k page 到buffer cache中,出现下面的ERROR消息。

ERROR: invalid page in block 1226710 of relation base/xxxxx/xxxx

2, 如果不正常的数据在PostgreSQL数据库buffer cache的一部分,则PostgreSQL将假设没有错误,并尝试操作buffer cache中的错误数据。结果不可预测;可能会导致各种错误消息,崩溃和故障模式-甚至返回不包含任何错误消息的不正确数据。

PostgreSQL如何检查页面有效性

PostgreSQL在page block上执行两个主要的“有效性检查”。您可以在函数PageIsVerified()中阅读代码,但在此将对其进行总结。您可以从错误消息中得知哪个有效性检查失败。这取决于您是否在错误之前看到了另一个警告。该警告是这样的

WARNING: page verification failed, calculated checksum 3482 but expected 32232

1, 如果不存在以上警告,则表明 page header 未通过基本的健全性检查。 这可能是PostgreSQL内部和外部的问题所引起的。
2, 如果您看到上述警告,则表示block中记录的checksum和与为该block计算的checksum不匹配。 这很可能表明数据库底层存在问题-操作系统,内存,网络,存储等。

 

在PostgreSQL 13中每页的前24个字节由一个页头(PageHeaderData)组成。Page header data layout详细介绍了其格式。第一个字段跟踪与此页面相关的最新WAL条目。如果启用了数据校验和,则第二个字段包含页面校验

Page Header Data Layout

Field Type Length Description
pd_lsn PageXLogRecPtr 8 bytes LSN: next byte after last byte of WAL record for last change to this page
pd_checksum uint16 2 bytes Page checksum
pd_flags uint16 2 bytes Flag bits
pd_lower LocationIndex 2 bytes Offset to start of free space
pd_upper LocationIndex 2 bytes Offset to end of free space
pd_special LocationIndex 2 bytes Offset to start of special space
pd_pagesize_version uint16 2 bytes Page size and layout version number information
pd_prune_xid TransactionId 4 bytes Oldest unpruned XMAX on page, or zero if none

All the details can be found in src/include/storage/bufpage.h.

–data-checksums
在数据页上使用校验和,以帮助检测I / O系统的损坏,否则这些损坏将是静默的。启用校验和可能会导致明显的性能损失。如果设置,将为所有数据库中的所有对象计算校验和。所有校验和失败都将在pg_stat_database视图中报告。

从版本11开始的PostgreSQL本身具有一个命令行实用程序,用于扫描一个关系或所有内容并验证每个块上的校验和。这就是所谓的pg_verify_checksums在V11和pg_checksums在V12。 缺点:首先,此实用程序要求您在数据库运行之前先关闭它。如果数据库启动,它将引发错误并拒绝运行。其次,您可以扫描单个关系,但是不能说出它在哪个数据库中……因此,如果OID存在于多个数据库中,则无法只扫描您关心的关系。

另外还有一些外部插件如Credativ的高级工程师已经发布了pg_checksums的增强版本,版本可以验证正在运行的数据库上的校验和。

如果报错,我们可以使用UNIX命令转储,检查cksum值

$ dd status=none if=base/xxx/xxx bs=8192 count=1 skip=250 | od -A d -t x1z -w16
0000000 00 00 00 00 e0 df 6b b0 ba 3a 04 00 0c 01 80 01  >......k..:......<
...

另外也可以使用pg_filedump程序查看更详细的信息,类似oracle的BBED read,该实用程序有很多选择。验证校验和(-k),仅以偏移量250(-R 250 250)扫描一个块,甚至将元组(表行数据)解码为人类可读的格式( -D int,int,int,charN)。还有另一个参数(-f)甚至可以告诉pg_filedump内联显示hexdump / od样式的原始数据

$ pg_filedump -k -R 250 250 -D int,int,int,charN base/16385/16492

*******************************************************************
* PostgreSQL File/Block Formatted Dump Utility - Version 11.0
*
* File: base/16385/16492
* Options used: -k -R 250 250 -D int,int,int,charN
*
* Dump created on: Fri Nov  8 21:48:38 2019
*******************************************************************

Block  250 ********************************************************
<Header> -----
 Block Offset: 0x001f4000         Offsets: Lower     268 (0x010c)
 Block: Size 8192  Version    4            Upper     384 (0x0180)
 LSN:  logid      0 recoff 0xb06bdfe0      Special  8192 (0x2000)
 Items:   61                      Free Space:  116
 Checksum: 0x3aba  Prune XID: 0x00000000  Flags: 0x0004 (ALL_VISIBLE)
 Length (including item array): 268

 Error: checksum failure: calculated 0x44ba.

<Data>------
 Item   1 -- Length:  121  Offset: 8064 (0x1f80)  Flags: NORMAL
COPY: 15251	1	0
 Item   2 -- Length:  121  Offset: 7936 (0x1f00)  Flags: NORMAL
COPY: 15252	1	0
 Item   3 -- Length:  121  Offset: 7808 (0x1e80)  Flags: NORMAL
COPY: 15253	1	0

Thanks Jeremy_schneider share your knowledge

打赏

,

对不起,这篇文章暂时关闭评论。