포스트그레SQL 테이블 복구 방법

포스트gresql 테이블에서 발생하는 ‘missing chunk’ 오류로 인해 일일 백업이 실패하던 문제에 대해 이 글을 씁니다. 결국 문제를 해결했고, 동일한 문제를 겪는 다른 분들께 도움이 될 수 있도록 제가 사용한 방법을 정리해 보았습니다. 이것은 postgres missing chunk 오류를 올바르게 해결하는 방법이나 전문적인 지침이 절대 아닙니다. 저는 전문가가 아니며, 많은 지식이 없는 상태에서 진행했지만 결국 해결이 됐기 때문입니다.

백업 중 발생한 오류는 다음과 같습니다:

 pg_dump: error: Dumping the contents of table "stylesheet_cache" failed: PQgetResult() failed.
 pg_dump: error: Error message from server: ERROR:  missing chunk number 0 for toast value 1903804 in pg_toast_22663
 pg_dump: error: The command was: COPY public.stylesheet_cache (id, target, digest, content, created_at, updated_at, theme_id, source_map) TO stdout;

즉, 문제는 stylesheet_cache 테이블에 있었고, 오류 메시지는 ERROR: missing chunk number 0 for toast value 1903804 in pg_toast_22663이었습니다.

저는 Docker에서 Discourse를 사용 중이므로, 다음과 같은 작업을 수행했습니다.

ssh into the server
cd /path/to/discourse
./launcher rebuild app
su postgres -c "psql discourse"

postgres에 접속한 후, 문제가 해결될지 모르겠지만 테이블을 REINDEX 해 보았습니다.

discourse=# select reltoastrelid::regclass from pg_class where relname = 'stylesheet_cache';
      reltoastrelid      
-------------------------
 pg_toast.pg_toast_18396
(1 row)
REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_18396;
VACUUM analyze stylesheet_cache;

다시 백업을 시도했지만 여전히 실패했습니다. 그래서 손상된 부분을 찾아야 했습니다.

다음 쿼리로 테이블의 총 행 수를 계산했습니다:

select count(*) from stylesheet_cache;

행 수는 2260건이었습니다.

손상된 정확한 행을 찾아 삭제하기로 했습니다. 어떻게든 stylesheet_cache가 전체 DB를 망가뜨릴 수 있는 요소는 아닐 것이라고 가정했습니다. 앞서 언급했듯이 저는 전문가가 아니므로, 아마도 너무 큰 도박을 친 것일 수 있습니다. 이 작업을 수행할 때는 주의하세요. DB를 망가뜨릴 수 있습니다.

LIMIT와 OFFSET 쿼리를 사용하여 손상된 행을 찾았습니다.

select * from stylesheet_cache order by id limit 100 offset 0;

Missing chunk… 오류가 나올 때까지 offset과 limit을 조정하다가, LIMIT 1로 좁혀서 손상된 행의 offset을 찾았습니다. 제 경우엔 손상된 행이 5개 있었습니다.

sh 스크립트를 사용하면 더 적은 노력으로 해당 행을 찾을 수 있습니다. 저는 수동으로 진행해서 시간이 좀 걸렸지만, 다음과 같은 스크립트를 사용할 수 있습니다:

#!/bin/sh
j=0
while [ $j -lt 2260 ]
do
  psql -U postgres -d discourse -c "SELECT * FROM stylesheet_cache LIMIT 1 offset $j" >/dev/null || echo $j
  j=$(($j+1))
done

다음 명령으로 손상된 행의 id를 찾았습니다:

select id from stylesheet_cache order by id limit 1 offset 450;

id

----

11498

따라서 제 손상된 행의 id는 11498이었습니다.
다음으로 행을 삭제했습니다.

delete from stylesheet_cache where id = 11498;

손상된 행을 삭제한 후 다시 REINDEX를 수행했습니다.

REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_40948;
VACUUM analyze stylesheet_cache;

그리고 다시 백업을 시도했는데, 이번에는 성공했습니다. 이 postgres 복구 지침을 참고했습니다: Postgres error: Missing chunk 0 for toast value in pg_toast · GitHub

면책 조항: 이것은 전문가의 의견이 아니므로, 유사한 missing chunk 손상이 발생해 수정을 시도할 경우 신중하게 진행하시기 바랍니다.

3개의 좋아요