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
对不起,这篇文章暂时关闭评论。