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

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核4GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介:

标签

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.  

pic

观察到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;  

pic

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

接下来对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  

pic

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

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

pic

对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  

pic

执行vacuum analyze verbose pg_attribute;

vacuum analyze verbose pg_attribute;  

pic

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

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

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

select ctid from pg_attribute;  

pic

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

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

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

pic

小结

这个问题可能是尾部块回收的一个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>.  
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
关系型数据库 Java Go
解决 MyBatis-Plus + PostgreSQL 中的 org.postgresql.util.PSQLException 异常
解决 MyBatis-Plus + PostgreSQL 中的 org.postgresql.util.PSQLException 异常
1272 0
|
关系型数据库 PostgreSQL
PostgreSQL异常重启postmaster.pid处理
PostgreSQL异常重启postmaster.pid处理
258 0
|
7月前
|
SQL 关系型数据库 MySQL
PostgreSQL【异常 01】java.io.IOException:Tried to send an out-of-range integer as a 2-byte value 分析+解决
PostgreSQL【异常 01】java.io.IOException:Tried to send an out-of-range integer as a 2-byte value 分析+解决
517 1
|
关系型数据库 PostgreSQL
PostgreSQL异常宕机重启时间超长
PostgreSQL异常宕机重启时间超长
135 0
|
SQL druid Java
Java 执行 Postgresql Jdbc 类型异常时,复杂sql难定位的解决方案
Java 执行 Postgresql Jdbc 类型异常时,复杂sql难定位的解决方案
1420 0
Java 执行 Postgresql Jdbc 类型异常时,复杂sql难定位的解决方案
|
存储 SQL Perl
PostgreSQL plpgsql 存储过程、函数 - 状态、异常变量打印、异常捕获... - GET [STACKED] DIAGNOSTICS
标签 PostgreSQL , GET , STACKED , DIAGNOSTICS 背景 使用GET STACKED DIAGNOSTICS捕获异常时的STACK内容。 使用GET DIAGNOSTICS捕获运行过程中的状态值。
4637 0
|
SQL 关系型数据库 数据库
PostgreSQL sql文件编码引起的数据导入乱码或查询字符集异常报错(invalid byte sequence)
标签 PostgreSQL , 乱码 , 文件编码 背景 当用户客户端字符集与服务端字符集不匹配时,写入的多字节字符(例如中文)可能出现乱码。 例子 数据库字符集为sql_ascii,允许存储任意编码字符。
3772 0
|
关系型数据库 C语言 PostgreSQL
PostgreSQL 开启with-llvm(JIT)后,新增插件异常(clang: Command not found)处理
标签 PostgreSQL , llvm , clang , jit 背景 PostgreSQL 11版本开始引入了对JIT的支持,在OLAP类型的SQL有比较大的性能提升。 如果你使用的是YUM安装的PG,clang可能没有加入,在后期编译其他插件时可能遇到类似的报错: 比如pg_hint_plan插件 git clone https://github.
2984 0

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版