問題現象
今天突然被拉進一個群,說某地區友商推送編目結果報錯,在我們自己的卷宗系統上傳材料也一直轉圈,也刪除不了案件卷宗,重置模板也沒用,只有個別案件有問題。雖然這事兒不屬于我負責,但還是抽時間給看了一眼,其實問題很簡單,就是索引損壞了,估計之前有過異常斷電之類的場景導致的,在這里記錄一下。
排查過程
首先要來環境信息,并復現問題,通過瀏覽器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