PostgreSQL 末尾块收缩(如pg_type pg_attribute)异常和patch

标签

PostgreSQL , 数据块损坏 , pg_type , pg_attribute


背景

某些用户遇到的一些问题,报读数据块错误。

ERROR: colud not read block 15 in file "base/16386/12741": read only 0 of 8192 bytes

大概的意识是,第15个数据块,没有正确的读出数据,数据为0字节。

第一反应是数据块坏了。

根据路径,可以查询到损坏的是什么对象

select relname,relkind  from pg_class where pg_relation_filepath(oid)='base/16386/12741';  

返回  

pg_type

对pg_type对象执行vacuum full verbose,依旧报错

vacuum full verbose pg_type;  

ERROR: colud not read block 15 in file "base/16386/12741": read only 0 of 8192 bytes

执行vacuum verbose

vacuum verbose pg_type;  

INFO: "pg_type": found 79 removable, 500 nonremovable row versions in 13 out of 13 pages.

观察到pg_type只有13个page,而前面报错是读第15个块(page)异常。怀疑是与visibility map或freespace map相关文件的BUG。

PS: 每个数据文件,都会对应vm和fsm文件,如果是unlogged 对象,还有init后缀的文件作为标识。其实VM文件,每个PAGE对应2个BIT,表示页是否完全可见,是否为FREEZE状态等。而fsm文件是每个页的剩余空间,每个页用1个字节表示,所以可以表示1/256的精度。

检查pg_type是否已修复,执行select ctid from pg_type,扫描完所有结果

select ctid from pg_type;

虽然正常了,但是系统中还有报错的块。

接下来对pg_type表执行vacuum full verbose,发现还会报错,报的是另一个文件读取错误。

vacuum full verbose pg_type;  

ERROR: colud not read block 87 in file "base/16386/12753": read only 0 of 8192 bytes

通过报错的文件路径,查询得到这个报错是pg_attribute,因为vacuum full时需要查询pg_attribute(这个表存储的是每个字段的属性)元数据。说明这部分元数据也有损坏。

select relname,relkind  from pg_class where pg_relation_filepath(oid)='base/16386/12753';

对pg_attribute执行vacuum full verbose,报错相同。因为vacuum full时需要查询pg_attribute元数据

vacuum full verbose pg_attribute;  

ERROR: colud not read block 87 in file "base/16386/12753": read only 0 of 8192 bytes

执行vacuum analyze verbose pg_attribute;

vacuum analyze verbose pg_attribute;

从执行结果分析,pg_attribute这个表,只有86个数据块,而报错的是读取第87个数据块的错误。

执行完vacuum verbose, pg_attribute也修复了。

执行以下SQL扫全表,确认一下是否正确。

select ctid from pg_attribute;

执行select ctid from pg_attribute返回了85个数据块的数据(ctid从0开始编号)。

全表扫描没有出现错误,末尾为0的数据块已修复。

最后,执行vacuum full verbose 可以正常执行。

小结

这个问题可能是尾部块回收的一个BUG,至于怎么引起的,目前怀疑1.可能是Linux ext4文件系统使用data=writeback mount参数,操作系统或文件系统CRASH后导致的问题。2.可能是操作不当引起,例如文件系统进入只读状态,或者强制将数据库变成recovery状态. 3.可能是HOT技术相关的某个BUG,牵涉到vacuum(可以通过pageinspect观察ctid的重定向,是否指向了末尾的空块,可能性很小). 由于还没有找到复现方法, 与社区沟通中。

社区的patch

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=2523bef15e446d25d16b206bac3b6ef6ad6a8a7d

Fix WAL-logging of FSM and VM truncation.

When a relation is truncated, it is important that the FSM is truncated as
well. Otherwise, after recovery, the FSM can return a page that has been
truncated away, leading to errors like:

ERROR:  could not read block 28991 in file "base/16390/572026": read only 0
of 8192 bytes

We were using MarkBufferDirtyHint() to dirty the buffer holding the last
remaining page of the FSM, but during recovery, that might in fact not
dirty the page, and the FSM update might be lost.

To fix, use the stronger MarkBufferDirty() function. MarkBufferDirty()
requires us to do WAL-logging ourselves, to protect from a torn page, if
checksumming is enabled.

Also fix an oversight in visibilitymap_truncate: it also needs to WAL-log
when checksumming is enabled.

Analysis by Pavan Deolasee.

Discussion: <CABOikdNr5vKucqyZH9s1Mh0XebLs_jRhKv6eJfNnD2wxTn=_9A@mail.gmail.com>

Backpatch to 9.3, where we got data checksums.

如果您遇到读某个块只能读出0字节,可能和文中是同一个CASE,解决方法。

可以使用文中提到的QUERY,找到对应的对象名,如果对象是表或者物化视图,可以使用 vacuum analyze 名字; 来进行修复。

如果是索引,重建索引即可。

如果你不确定是哪个对象,或者有多个对象损坏,建议直接使用vacuum analyze;进行修复(全库).或使用如下命令对整个集群的所有数据生效。

vacuumdb -az  

这是postgresql的一个命令  

vacuumdb --help
vacuumdb cleans and analyzes a PostgreSQL database.  

Usage:
  vacuumdb [OPTION]... [DBNAME]  

Options:
  -a, --all                       vacuum all databases
  -d, --dbname=DBNAME             database to vacuum
  -e, --echo                      show the commands being sent to the server
  -f, --full                      do full vacuuming
  -F, --freeze                    freeze row transaction information
  -j, --jobs=NUM                  use this many concurrent connections to vacuum
  -q, --quiet                     don't write any messages
  -t, --table='TABLE[(COLUMNS)]'  vacuum specific table(s) only
  -v, --verbose                   write a lot of output
  -V, --version                   output version information, then exit
  -z, --analyze                   update optimizer statistics
  -Z, --analyze-only              only update optimizer statistics; no vacuum
      --analyze-in-stages         only update optimizer statistics, in multiple
                                  stages for faster results; no vacuum
  -?, --help                      show this help, then exit  

Connection options:
  -h, --host=HOSTNAME       database server host or socket directory
  -p, --port=PORT           database server port
  -U, --username=USERNAME   user name to connect as
  -w, --no-password         never prompt for password
  -W, --password            force password prompt
  --maintenance-db=DBNAME   alternate maintenance database  

Read the description of the SQL command VACUUM for details.  

Report bugs to <pgsql-bugs@postgresql.org>.  
时间: 2024-11-02 17:23:49

PostgreSQL 末尾块收缩(如pg_type pg_attribute)异常和patch的相关文章

PostgreSQL 最佳实践 - 块级增量备份(ZFS篇)方案与实战

背景 在实际的生产环境中, 当数据库越来越多, 越来越大. 备份可能会成为比较大的问题, 传统的逻辑备份对于大的数据库不适用(因为备份和还原可能是比较耗时的, 而且也不能回到任意时间点, 还会造成数据库膨胀(长时间repeatable read隔离级别), 好处是可以跨平台恢复, 可选恢复表等). 而基于XLOG的增量备份, 虽然备份可以在线进行,同时支持恢复到任意时间点,但是恢复需要APPLY从基础备份到恢复目标之间所有产生的XLOG,如果基础备份做得不频繁,那么恢复时可能需要APPLY的XL

postgre 异常-java连接postgresql报告的异常

问题描述 java连接postgresql报告的异常 org.postgresql.util.psqlException:????????:??????,???????????????? 想问一下这个异常怎么解决

PostgreSQL 10.0 preview 性能增强 - 间接索引(secondary index)

标签 PostgreSQL , 10.0 , 间接索引 , 第二索引 背景 我们知道,PostgreSQL的MVCC是多版本来实现的,当更新数据时,产生新的版本. 那么如果新版本不在同一个数据块的时候,索引也要随之变化,当新版本在同一个堆表的块里面时,则发生HOT UPDATE,不需要变更没有发生值改变的索引. 但是HOT总不能覆盖100%的更新,所以还是有索引更新的可能存在. 为了解决这个问题,PostgreSQL 10.0引入了第二索引(间接索引)的概念,即在PK或者UK之上,构建其他索引.

PostgreSQL 数据文件灾难恢复 - 解析与数据dump

标签 PostgreSQL , 数据文件 , pg_filedump , 安全 , TDE 背景 俗话说常在河边站哪有不湿鞋,作为一名战斗在一线的DBA或者开发者,可能有遇到过磁盘损坏,磁盘阵列损坏,如果有备份或者备库的话,还好. 如果没有备份,或者没有备库(通常有一些小型或者创业型的企业),那么遇到磁盘损坏或者其他原因(比如掉电文件系统损坏),导致数据库的数据文件并不完整时,如何从有限的资料中找出数据呢? 比如PostgreSQL,如果读到坏块,会报块不可读的错误,这种情况下通过设置zero_

PostgreSQL 10.0 preview 功能增强 - 匿名、自治事务(Oracle 兼容性)

标签 PostgreSQL , 10.0 , 匿名事务 , 自治事务 背景 PostgreSQL 10.0 通过session backendground实现了匿名事务,从此可以愉快的支持Oracle存储过程的自治事务了. 此前,我们需要通过dblink实现,或者通过匿名块+exception来实现,比较繁琐. <PostgreSQL Oracle 兼容性之 - plpgsql 自治事务(autonomous_transaction)补丁> <PostgreSQL Oracle 兼容性之

JAVA【异常二】异常处理机制

Java中异常提供了一种识别及响应错误情况的一致性机制,有效地异常处理能使程序更加健壮.易于调试.异常之所以是一种强大的调试手段,在于其回答了以下三个问题: 什么出了错? 在哪出的错? 为什么出错? 在有效使用异常的情况下,异常类型回答了"什么"被抛出,异常堆栈跟踪回答了"在哪"抛出,异常信息回答了"为什么"会抛出.   在Java 应用程序中,异常处理机制为:抛出异常,捕捉异常. 抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付运

【最近面试遇到的一些问题】运行时异常与一般异常有何异同

Throwable 是所有 Java 程序中错误处理的父类 ,有两种资类: Error 和 Exception .    Error :表示由 JVM 所侦测到的无法预期的错误,由于这是属于 JVM 层次的严重错误 ,导致 JVM 无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息. Exception :表示可恢复的例外,这是可捕捉到的. Java 提供了两类主要的异常 :runtime exception 和 checked exception . check

一篇不错的讲解Java异常的文章

六种异常处理的陋习你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗? 1 OutputStreamWriter out = ... 2 java.sql.Connection conn = ... 3 try { // ⑸ 4 Statement stat = conn.createStatement(); 5 ResultSet rs = stat.executeQuery( 6 "select uid, n

Java中异常机制的研究

首先Java的异常是面向对象的.一个Java的Exception是一个描述异常情况的对象.当出现异常情况时,一个Exception对象就产生了,并放到异常的成员函数里. Java的异常处理是通过5个关键词来实现的:try,catch,throw,throws和finally.1.异常处理: 在Java语言的错误处理结构由try,catch,finally三个块组成.其中try块存放将可能发生异常的Java语言,并管理相关的异常指针:catch块紧跟在try块后面,用来激发被捕获的异常:final