当pg在执行操作时,遇到如invalid page in block 335458 of relation base/16385/99454
所示的错误时,可能是遇到了数据页损坏的问题。
我们模拟一个页面损坏的例子看下。
模拟页面损坏
1.创建表test,插入2000行数据,找到test表在文件系统中的位置:base/13318/66051
## 创建表test
postgres=# CREATE TABLE test(id varchar(8) PRIMARY KEY);
CREATE TABLE
postgres=# ANALYZE test;
ANALYZE
## 插入2000行数据
postgres=# INSERT INTO test SELECT generate_series(1,2000)::TEXT;
INSERT 0 2000
postgres=# CHECKPOINT;
CHECKPOINT
## 定位test表在文件系统中的位置
postgres=# SELECT pg_relation_filepath(oid) FROM pg_class WHERE relname = 'test'
;
pg_relation_filepath
----------------------
base/13318/66056
2.关闭数据库,使用dd命令模拟文件损坏。
## 关停数据库(关停数据库是防止内存中的页面刷回磁盘覆盖修改后的文件)
$pg_ctl -D $PGDATA stop
##使用dd模拟文件损坏
$ yes 'this is garbage' | dd of=base/13318/66056 bs=1024 seek=0 count=1 conv=notrunc
1+0 records in
1+0 records out
1024 bytes (1.0 kB, 1.0 KiB) copied, 0.000326 s, 3.1 MB/s
3.重新启动数据库,查询表中数据, 出现invalid page in block 0
的错误。
## 查询出错
postgres=# select * from test;
ERROR: invalid page in block 0 of relation base/13318/66056
## 但是查询非block 0的数据则不会出错。
postgres=# select *,ctid from test where ctid='(1,1)';
id | ctid
-----+-------
227 | (1,1)
解释
接下来,我们分析下ERROR: invalid page in block 0 of relation base/13318/66056
这个报错的详细信息。
其中base/13318/66056
, 13318表示数据库OID,66056表示表的relfilenode。block 0则表示文件的块号。
遇到这种情况时,我们需要尽快将数据恢复。恢复的方法可以从备份中恢复,或者如果有从库并且从库数据没有损害的情况,故障转移到从库也可以。
如果你想看下被损害的文件的详情,可以根据块号定位到具体的数据文件,上面的例子中block为0,很明显在是第一个分段文件。如果数据很大,被分成了多个文件,比如660565、660565.1、660565.2、660565.3、…。这时我们可以根据数据文件大小(默认是1G),来定位具体是哪个文件。
假设出错的块号是block_number = 335458,我们可以使用如下方式计算具体的分段文件segment_number、页偏移page_offset、字节偏移byte_offset,然后可以借助一些工具查看文件信息,比如dd、hexdump
等。
page_size = 8k
pages_per_segment = segment_size / page_size = 1GB/8KB = 131072
segment_number = block_number / pages_per_segment = 2
page_offset = block_number % pages_per_segment = 73314
byte_offset = page_offset * page_size = 600588288
此外,pg支持checksum,用以发现数据因磁盘、 I/O损坏等原因造成的数据异常。如果开启了检验和,如果页面发生了损坏,在你查询的时候可能出现如下报错:
postgres=# select * from test;
WARNING: page verification failed, calculated checksum 26030 but expected 24935
ERROR: invalid page in block 0 of relation base/13318/66061
会有warning提示我们页校验失败,以帮助我们尽快发现因一些原因导致的数据不一致的问题。
查询系统是否开启了开启了checksum,可以使用如下命令:
postgres=# SHOW data_checksums;
data_checksums
----------------
on
对数据可靠性要求高的业务可以考虑打开,但是需要注意的是打开这个会带来一定的资源消耗。
总结
形如invalid page in block 335458 of relation base/16385/99454
这种错误时,可能是遇到了数据页损坏的问题,我们可以根据它的提示信息定位到具体的数据位置。遇到这种错误时,我们应该尽快做数据恢复,比如从备份恢复或者故障转移等等。
参考:
https://www.cybertec-postgresql.com/en/how-to-corrupt-your-postgresql-database/
https://pganalyze.com/docs/log-insights/server/S6
https://www.modb.pro/db/25829
点个“赞 or 在看” 你最好看!
👇👇👇 咔片谢谢各位老板啦!!!
原文始发于微信公众号(PostgreSQL运维技术):pg中遇到的invalid page in block 335458 of relation base/16385…的错误?
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/45634.html