现场问题排查-postgresql某表索引损坏导致指定数据无法更新影响卷宗材料上传
问题现象
今天突然被拉进一个群,说某地区友商推送编目结果报错,在我们自己的卷宗系统上传材料也一直转圈,也删除不了案件卷宗,重置模板也没用,只有个别案件有问题。虽然这事儿不属于我负责,但还是抽时间给看了一眼,其实问题很简单,就是索引损坏了,估计之前有过异常断电之类的场景导致的,在这里记录一下。
排查过程
首先要来环境信息,并复现问题,通过浏览器F12控制台观测,指定案件上传卷宗任意材料时后端上传材料接口都会稳定返回一个数据库错误,关键字是“PSQLException: ERROR: index idx_ws_xxx contains unexpected zero page at block 1280517 Hint: Please REINDEX it.”。
错误提示其实已经很明显了,就是说索引损坏了,建议重建索引。所以就直接告诉现场重建索引就行了,考虑到现场版本比较低(PG9.6.3)不支持REINDEX CONCURRENTLY,给现场写了类似以下脚本让其执行后观察:
-- 查询索引定义脚本,供后续重建索引使用(第一列就是索引创建脚本)
SELECT indexdef, * FROM pg_indexes where indexname = 'idx_ws_xxx';
-- 删除损坏的索引
DROP INDEX idx_ws_xxx;
-- 在索引定义脚本中加上CONCURRENTLY关键字,防止创建索引时阻断表业务操作,毕竟有问题的数据很少,正常业务很多
CREATE INDEX CONCURRENTLY idx_ws_xxx ...;
好几个小时后问现场,现场答复还在执行中,虽然这个表有五千万的数据量,但也不至于这么慢吧?
-- 使用以下脚本查询数据库所有连接情况
select * from pg_stat_activity;
-- 使用以下脚本确认在运行的连接情况
select datname, pid, application_name, backend_start, wait_event_type, query, * from pg_stat_activity;
上面脚本能看到两个关键连接,一个是删除索引的脚本处于激活状态,且一直在等待锁,另一个是重建索引的表上有个autovacuum在跑且开始时间确实在drop索引的脚本之前,所以不需要再追踪具体锁进程也能猜出来该表自动清理任务影响了索引重建。
-- 先暂停该表的自动清理选项
alter table t_ws set (autovacuum_enabled = false);
-- 再杀掉该表的自动清理任务(自动清理是带事物的,杀掉只会导致数据回滚,不会损坏表)
select pg_terminate_backend(任务连接的pid);
上面脚本执行完发现还是会锁定,再次观察pg_stat_activity结果发现pg自动拉起来一个新的进程继续跑autovacuum。
-- 暂停数据库级别的自动清理选项
alter system set autovacuum = off;
-- 刷新配置,不用重启数据库
select pg_reload_conf();
-- 也可以用 show autovacuum 语句查看当前生效的配置值-- 删除索引并重建索引-- 恢复数据库级别的自动清理选项
alter system set autovacuum = on;
-- 刷新配置,不用重启数据库
select pg_reload_conf();
再次验证,搞定!
参考资料
PG9.6 REINDEX命令:http://postgres.cn/docs/9.6/sql-reindex.html
PG12 REINDEX命令:http://postgres.cn/docs/12/sql-reindex.html