记一次PostgreSQL数据文件的损坏与修复
PG数据文件损坏了,咋损坏的?下面我来说点废话,讲讲这个事情的经过。
春节后开工时发现服务器的CPU和磁盘IO居高不下,经一番排查发现是硬盘读写很慢,停掉了所有程序后CPU下来了,但查看文件时依旧很慢。
这台服务器是旧电脑拿来做测试机,硬盘是系统分区SSD加一个数据分区HDD,所以咱合理怀疑机械盘有坏道影响了读写性能。
看了一下HDD中存的文件不是很大,尝试把文件备份到SSD时,发现PG的数据文件已经损坏了,rsync过程中不断报错。
好巧不巧我没对PG做备份,那咋办?只能尝试修复了。
在确认完其他文件未损坏后,我直接把$PGDATA
目录下载到我的电脑,尝试通过WSL中的PG环境修复数据库。
上网搜索相关案例
这个时候当然是先通过AI搜索的同时还能提供解决办法,毕竟这种问题我也是第一次遇到,我首先选择了最近非常火的DeepSeek
,结果没有结果,回了我一句系统繁忙。。
然后问了智谱清言
,他让我直接通过pg_dump把数据导出来,胡扯了一通后,他让我通过wal
记录查找checkpoint
、再通过事务id
恢复到最后一个checkpoint
。
后来再经过一番原始搜索,找到了几个供参考的帖子,咱们距离成功已经不远了。
修复过程
- 首先尝试1号帖子和2号帖子的方案
原先咱们在服务器上执行SQL查询时会报这个错:无法在文件"base/17506/2703"中读取块3
。
也是就是说损坏的数据库oid为17506,损坏的对象id为2703,那么直接查一下是哪个对象。这时有报错了:1
select * from pg_class where relfilenode = 2703
could not open file "base/17506/2703": No such file or directory
。
这是为啥呢?因为文件已经损坏了,从服务器拉下来的时候直接跳过这个文件了,这样也没法尝试3号帖子的方案了。。 - 试试AI给出的方案
查找最新检查点1
pg_controldata -D /var/lib/postgresql/12/main
查找最新检查点对应的事务id1
pg_waldump -b -s C/46000400 -p /var/lib/postgresql/12/main
可惜了这里也报错,并且查询出来的事务id对咱们没用。 - 另辟蹊径
既然数据文件已经损坏了,而且损坏的不是所有文件,说明只要有办法恢复文件的完整性,就可以保住未损坏文件对应的数据。
那么咱们直接给不存在的文件填充为空。1
dd if=/dev/zero of=/var/lib/postgresql/12/main/base/17506/2703 bs=1M count=1
此时可以看到,再次执行查询语句的时候,报的是另一个错,那么咱们就按照提示重建索引。1
reindex index pg_cast_source_target_index;
这时问题又来了,重建索引后查询不会报错,但是没数据呀。所以我又检查了其他的表,结果又让我发现一个文件不存在,果不其然这些数据对象是有其他索引相关联的。
按照这个思路把所有的表都校验了一遍,现在不报错了,但是只有几个表是有数据的,这不合理呀,缺失的文件不到10个,不能丢这么多数据吧。
先不管这么多了,已经能正常查询数据了,先把整个库导出一下吧。1
pg_dump -v -d demo_uav -f demo_uav.sql
你猜怎么着,居然还没完事,那就继续填充空文件和重建索引呗,就这么一直重复操作,最终皇天不负有心人,数据库被我给dump下来了。
抱着试一试的想法,我再执行了一次SQL,就查刚刚没数据的uav表,结果有数据了。
于是乎我有开始检查所有表,最后发现只有一张表是丢数据的,好在这个库在2个月前备份过一次,而且这张表也不是经常变动的,一共少了十几条数据,真是万幸。
修复硬盘坏道
前面已经把硬盘数据备份到固态盘了,这会儿可以放心格盘。
1 | # 移除挂载 |
恢复数据库
重新创建数据库并把sql文件导入
1 | psql -U postgres -d demo_uav -f /mnt/data/demo_uav.sql |
重启服务并测试硬盘读写
这里就不再赘述了,到此整个修复过程就结束了,仅此记录,希望对其他人也有帮助。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 没事淦的博客!