이 글은 어제 이곳 DB 서버 사고에 대한 처리 과정을 기록해 두는 글입니다. 글 성격이 투토리얼이기 보다는 DBA 긴급 처리 문서에 더 가깝습니다.
PostgreSQL 서버를 어느정도 관리하실 수 있는 분을 대상으로 그냥 기록해 두겠습니다. 이해가 잘 안가시면 QnA에서 문의 하시든지, 아니면, 열심히 혼자서 메뉴얼보면서 공부하시든지. :)
0. 사태의 원인
이곳 db 서버의 PGDATA 디렉토리의 디스크 사용량이 그 파티션의 최대용량을 초과 하면서, OS 차원의 파일 쓰기에 오류가 발생했습니다.
이때, 쓰기가 별로 없는 서버였다면, 별 문제가 없었을진데, 이곳 게시판들의 검색은 그 검색 결과를 임시테이블에 저장하는 방식을 택하지는지라, 특히나 파일 쓰기가 꽤 자주 일어납니다.
즉, 여기서 완전 꼬여버렸습니다.
임시 테이블의 정보를 담는 pg_class, pg_class, pg_index, pg_attribute, pg_type 의 system catalog 테이블들은 그 정보가 담겨지고, 실재 물리적인 파일은 0byte 의 전혀 쓸모 없는 형태로 만들어지면서 postmaster 놈은 계속에서 오류를 알려주고 있는 과정에서 누군가가 게시물 작성을 하면서, 게시물 작성 과정에서 발생하는 4-5가지의 트리거작업을 하면서, pg_clog, pg_xlog 디렉토리의 undo, redo 정보를 담는 파일 조차 손상을 입었습니다.
1. pg_resetxlog 사용하기
이명령은 db server가 정상적으로 실행될 수 없는 상황에서 가장 마지막 선택하는 방법입니다. (물론 보다 더 저수준으로 자료만이라도 살리는 방법도 있겠지만)
이 명령을 사용하기 위해서는 먼저 PostgreSQL 서비스를 중지해야합니다.
일단 pg_resetxlog PGDATA
명령으로 pg_xlog 디렉토리 이하의 redo, undo 정보부터 바르게 정리합니다. (정 안되면, pg_xlog 이하 모든 파일을 지우고, pg_resetxlog 명령을 이용해서 다시 만드는 방법도 있겠지요)
2. pg_clog 자료 복구하기.
일단 깨어진 clog 파일이 어느 것인지 부터 찾아야합니다.
참고고, clog 디렉토리 안에 있는 자료는 commit 되지 않고 비정상 종료된 - 정상 종료되면 당연히 rollback 됩니다 - 트랜젝션의 변경 정보가 담겨집니다. 서버가 가동될 때, 이 정보가 있으면, pg_xlog 디렉토리 안에 있는 해당 자료를 찾아서 rollback을 완벽하기 시키겠지요.
(그 깊숙한 곳 까지는 공부를 더 해봐야알겠네요)
아무튼 어떠한 트랜젝션이 없다고 가정한다면, clog 파일은 그 파일이 정상적으로 있느냐 없느냐만 체크할 수 있으면 됩니다.
즉, 다른 정상적인 clog 파일을 복사해서 손상된 clog 파일에 덮어쓰면 되겠지요.
cd PGDATA/pg_clog; cp 0000 0001
이런식으로
3. 서버 재가동
일단 여기까지 하면, postmaster가 정상적으로 실행될 수 있으면, connect 까지도 가능할 것입니다.
4. catalog 테이블 정리
문제는 여기서부터 아주 인내심을 요하는 데이터 정리 작업을 해야합니다.
만일 이곳 서버처럼 임시 테이블을 빈번히 사용하는 상태라면, 임시테이블 삭제가 정상적으로 이루워졌는지 살펴보고, 만일 그렇지 못한 상태에서 종료되었다면, pg_class, pg_index, pg_attribute 등 아무튼 임시 테이블이 만들어지면서 변경되는 catalog 테이블들을 정상상태로 만들어야합니다.
(손상된 임시테이블 수동으로 정리하기)
4.1. select oid from pg_class where relname 'pg_temp_%'
형태로 모든 임시 테이블들의 oid를 구하고, 그놈들 기반으로 구성된 column (pg_attribute), index(pg_index) 의 관련 데이터들을 모두 지워야겠지요. 그리고 마지막에 pg_class 도 지우고.
이때 주의하셔야할 사항은 pg_toast_% 테이블이 pg_temp_% 테이블과 관련이 있을 수도 있습니다. 이것도 함께 지워야한다면, 같이 삭제해야할 것입니다.
4.2. 그리고 몇가지 catalog 테이블을 더 손봤는데, 기억이 안남. -.-
4.3. 다음은 pg_class의 해당 oid 들의 물리적인 파일을 지우는 일이 남았습니다. (자신 없으면 지우지 않으셔도 괜찮습니다, 괜히 잘못 지웠다가 예상치 못한 데이터 파일이 삭제 될 수도 있으니)
5. vacuum -f
-f 옵션은 데이터도, 인덱스도 모두 새로 깔끔하게 만드는 것을 의미합니다. 데이터가 많다면, 시간이 꽤 걸리는 작업입니다.
6. 모든 데이터가 제대로 정리 되었다면,
안전하게 pg_dump 로 dump 받고, 다시 새로운 db에 restore 해보고, 정상적으로 작동한다면, 그 새로운 db를 기존 것과 바꾸어 사용하면 끝납니다.
(물론 어제 사태처럼 디스크 공간이 부족해서 발생한 것은 이런 식의 완벽한 처리가 불가능하겠지만, 아무튼 최종 마무리는 새로운 db를 만들고 그곳에 다시 정상적인 restore 하는 것이 제일 안전할 것입니다)
--
오후 시간 내내 이 문제를 풀어가면서 꽤 많은 경험을 하게 되었네요.
개인적으로 꽤 즐거운(?) 경험이었습니다.
좀처럼 발생하지 않는, 그러나 발생하면 거의 대책이 안서는 사태를 수습했다는 것에 뿌듯하기도 하고...
아무튼 이런 심각한 db 사고의 복구를 한번 더 해보고싶네요.
|