본문 바로가기
APM

InnoDB 테이블 손상(깨어진)시 강제 복구

by 누피짱 2014. 7. 3.

MyISAM과 달리 InnoDB 테이블들은 매우 안정적이며, 왠만해서는 데이터 파일이 깨어지는 경우는 거의 경험하지 못했다.

하지만, 데이터 파일이 깨어진다면 어떻게 해야 할까 ?. DBMS 벤더를 불문하고 손상된(깨어진) 데이터 파일을 복구한다는 것은 쉽지 않은 문제이며 위험도 크다.

이런 비 정상적인 현상은 어느 DBMS에서나 발생할 수 있는 현상이며, 이를 위해서 우리는 데이터베이스를 그렇게 열심히 백업하고 있었던 것이다.

만약, 백업마저도 복구가 안 된다면, 결국 지금의 깨어진 데이터 파일이라도 어떻게든 복구를 해야 한다.

하지만, InnoDB는 myisamchk와 같은 별도의 복구 도구를 제공하지 않는다.

손상된 InnoDB 테이블의 복구는 우선 MySQL을 기동시켜서 데이터를 덤프(mysqldump, SELECT INTO OUTFILE…)를 받는 것이 유일한 방법이다.

하지만, InnoDB는 Boot-up 과정에서 여러 가지 체크 및 정리 작업들을 하게 되는데, 이 중에서 하나라도 문제가 있을 경우 시작이 되지 않는다. (MySQL이 시작도 안 되는데 어떻게 덤프를 받지? ㅠㅠ)

그래서 MySQL의 설정 옵션 중에서 "innodb_force_recovery" 라는 설정 변수를 제공하고 있다. 

아래와 같이 MySQL의 설정 파일(my.cnf, my.ini)에 설정하면, 이 설정 값에 의해서 InnoDB에게 어떤 체크나 정리 작업을 건너뛰어야 할지를 알려 줄 수 잇다.


## 0 ~ 6까지의 값 중에서 하나를 설정 (0은 정상 상태인 경우이며 그 이상의 경우 강제 복구모드에 해당됨)

innodb_force_recovery = 1



기본 설정 값은 "0" 인데, 이는 InnoDB에게 모든 체크와 정리 작업을 정상적으로 실행하도록 명령하는 것이다.


그 이외의 설정 값은 모두 비 정상적인 상황을 위한 설정 값이며, 일반적인 서비스 환경에서는 사용하면 안 된다.

또한 "0"이 아닌 그 이외의 값을 설정하게 되면, InnoDB는 복구 모드라고 가정하고 SELECT 이외의 데이터를 변경하는 SQL들은 모두 처리를 거절해 버린다.



각 설정값별 복구 내용과 방식을 간단히 살펴보자. 


·         1 ( SRV_FORCE_IGNORE_CORRUPT )

데이터 파일의 손상된 페이지가 발견되어도 무시하고 MySQL을 기동시킨다.  일단 MySQL이 기동되면, SELECT * FROM tbl_name; 명령문을 실행하여 데이터를 덤프하여 다시 적재하거나 다른 데이터베이스로 이전하는 것이 좋다. 이 때, 손상된 인덱스 레코드와 페이지는 모두 건너뛰게 된다. (즉, 무시해 버리므로 데이터를 잃게 된다.)

에러 로그 파일에 "Database page corruption on disk or a failed "라고 출력되는 경우, 대부분 이 케이스인데 이는 테이블 스페이스의 페이지가 손상되어서 발생하는 문제이다. 이 경우에는 이 모드로 MySQL의 기동 후, mysqldump나 SELECT INTO OUTFILE...을 이용하여 덤프 및 재 적재가 가능하다.


·         2 ( SRV_FORCE_NO_BACKGROUND )

InnoDB의 여러 가지 Background thread들 중에서 Main thread를 시작하지 않고 MySQL을 기동시킨다. InnoDB의 경우 트랜잭션과 동시성 향상(MVCC)을 위해서 Undo 정보를 보존하게 되는데, 이 Undo 정보는 변경되기 전 데이터를 가지게 된다. 이러한 Undo 정보는 여러 가지 상황에 맞춰서 적절한 시점에 삭제가 되어야 하는데 이 작업을 Main thread가 처리한다 (이 작업을 Purge라고도 부른다.). 그런데 만약 MySQL 의 시작 과정에서 InnoDB가 이러한 Purge 작업 중 오류를 발생시킨다면, MySQL의 기동 시에 Main thread를 시작시키지 않기 때문에 Purge 작업 중의 오류를 피할 수 있게 되므로, 일단 MySQL을 시작시킬 수는 있게 된다. Undo 정보는 InnoDB의 시스템 테이블 스페이스에 관리되기 때문에, 이 경우에는 전체 데이터베이스를 덤프 받은 후 다시 MySQL 서버를 구성해야 한다.


·         3 ( SRV_FORCE_NO_TRX_UNDO )

MySQL을 종료하던 시점에 만약 진행 중인 트랜잭션이 있었다면, MySQL은 그냥 단순히 그 Connection을 강제로 끊어 버리게 된다. 그 이후 별도의 정리 작업은 진행하지 않게 된다. 즉 MySQL은 종료되었지만, 진행 중이던 트랜잭션의 정리 작업은 하지 않게 되는 것이다. MySQL이 다시 시작하게 되면, InnoDB 엔진은 트랜잭션 로그(Redo log라고도 함)를 읽어서 다시 처리 해주고(이 작업을  Roll forward라고 함), 최종적으로 어떤 트랜잭션이 완료되지 않고 Connection이 종료되었는지 판단 후, 그 트랜잭션들은 InnoDB 엔진이 Rollback을 시키게 되는데, 만약 Undo 영역이나 다른 관련된 데이터들이 손상된 경우에는 Rollback 처리를 해줄 수 없게 되는데, 이 경우에 사용하는 복구 모드이다. 이 경우에는 사실은 Rollback되어야 하지만, 실제 데이터 파일에는 그 데이터가 남아 있을 수 있다. (이 부분은 Binary log나 Application의 로그를 통해서 수동으로 보완해 주거나 무시하는 방법밖에 없다.)


·         4 ( SRV_FORCE_NO_IBUF_MERGE )

MySQL의 InnoDB는 INSERT, UPDATE, DELETE 등의 데이터 변경 작업으로 발생하는 인덱스 변경 작업들을 상황에 따라서 즉시 실행할 수도 또는 나중에 처리하도록 지연시킬 수 도 있다. 이렇게 나중에 처리하도록 지연시키기 위해서는 변경 내용을 어딘가에 기록해 두어야 하는데, 그 용도로 사용되는 버퍼가 "Insert Buffer"이다. 이 Insert Buffer의 내용은 언제 데이터 파일에 병합(Merge)될지 알 수 없다. MySQL을 종료해도 병합되지 않을 수 있는데, 만약 MySQL이 재 시작 되면서 Insert Buffer의 손상을 감지하게 되면 Insert Buffer의 병합 작업이 실패하고 MySQL이 기동하지 못하게 된다. 이 경우 사용할 수 있는 강제 복구 모드이다. (이 경우에는 테이블 통계 정보 갱신을 유발하는 작업들을 해서는 안 된다. 주로 DDL이나 ANALYZE 명령 등). Insert Buffer는 실제 데이터와 관련된 부분이 아니라 인덱스에 관련된 부분이라 테이블을 덤프 후 다시 적재하면 처리될 수도 있고, 아니면 단순히 "ALTER TABLE tbl_name ENGINE=InnoDB;" 명령만으로 해결될 수도 있다.


·         5 ( SRV_FORCE_NO_UNDO_LOG_SCAN )

복구 모드 3 ( SRV_FORCE_NO_TRX_UNDO )의 처리와 비슷하며, 이 모드에서는 Undo 로그를 완전히 무시하고 완전히 종료되지 않은 트랜잭션(COMMIT/ROLLBACK되지 않은)을 모두 COMMIT된 것으로 처리해 버린다.  또한 이 모드에서는 Undo 로그를 전혀 참조하지 않는 형태로 강제 복구 시킨다.


·         6 ( SRV_FORCE_NO_LOG_REDO )

이것은 MySQL 서버가 재 시작되기 전 가장 뒤에 발생한 체크 포인트 이후의 모든 트랜잭션을 버리고 복구 시키는 모드이다. 당연히 Redo 로그를 참조하지 않으므로 Roll forward라는 작업도 하지 않고 강제 복구시키게 된다. Redo 로그가 손상된 경우 이 모드로 강제 복구가 가능하다.


여기서 설명된 강제 복구 모드는 그 설정 값이 높아질수록 손실되는 데이터가 많아지기(복구 가능한 데이터가 적어지기) 때문에, 가능한 강제 복구 모드를 낮은 것(1 -> 2 -> 3 -> 4 -> 5 -> 6)부터 시도해 볼 것을 추천한다.


아래 내용은 HighPerformanceMySQL 블로그에서 발췌한 내용을 번역한 것인데, 같이 참조하면 좋을 듯 하다.

InnoDB 테이블이 손상되는 경우는 상당히 희박

Double write, Checksum 그리고 기타 Validation 로직들과 버그 보완으로 인해서, 실제로 MyISAM에 비해서 InnoDB 테이블 스페이스 및 데이터 파일은 상당히 안정적이다.


대부분의 손상은 인덱스에서 발생

많은 사람들이 경험하는 InnoDB 데이터 파일의 손상은 80~90% 정도가 InnoDB 인덱스 (Secondary index)에 발생한 손상인 경우이며, 이 경우에는 단순히 ALTER TABLE 또는 데이터 덤프 및 재 적재만으로 해결된다. 복구 모드 "1 ( SRV_FORCE_IGNORE_CORRUPT )" 참조.


이 이외의 InnoDB 테이블의 문제점들의 경우는 덤프 및 적재

이 이외의 복잡한 형태의 장애에 대해서는, (아주 심한 경우가 아니라면)데이터베이스 전체를 덤프하고 다시 적재하는 것으로 해결될 수 있다. 하지만, 가장 최근의 백업에 Binary log를 Replay (재 실행)해주는 것보다 빠를지는 상황을 적절히 판단해서 결정하는 것이 좋을 듯 하다.



이래도 저래도 안 되는 경우에는(대표적으로 InnoDB의 시스템 테이블 스페이스가 손상된 경우) 아래 URL의 도구를 참조하는 것도 도움이 될 수 있을 듯 하다.

(사용해 본 경험이 없어서, 얼마나 작동할지는 잘 모르겠다.)

http://code.google.com/p/innodb-tools/

https://launchpad.net/percona-innodb-recovery-tool

댓글