[MySQL - 강제 복구 모드 innodb_force_recovery]

테이블 손상이 발생할 수 있는 경우

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

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

 

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

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

 

3. 이외

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

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

 
 
 
 
각 설정값 별 복구 내용과 방식
 
 
 
1 ( SRV_FORE_IGNORE_CORRUPT ) 
  • 손상된 페이지가 발견되어도 무시하고 mysql를 가동합니다. 기동되면 테이블을 덤프하여 복구시키거나 다른데이터베이스로 이전하는것이 좋습니다. (손상된 레코드와 페이지는 모두 건너뛰게 됨으로 데이터를 잃게 됩니다.)
※ 에러 로그 파일에 "Database page corruption on disk or a failed"라고 출력되는 경우, 대부분 이 케이스인데 이는 테이블 스페이스의 페이지가 손상되어서 발생하는 문제이며, 이 경우에는 이 모드로 MySQL의 기동 후 mysqldump나 SELECT INTO OUTFILE...을 이용하여 덤프 및 재 적재가 가능합니다.   
 
 
 
2 ( SRV_FORCE_NO_BACKGROUND ) 
  • 메인 쓰레드(InnoDB의 경우 트랜잭션과 동시성 향상(MVCC)을 위해서 Undo 정보를 보존하게 되는데, 이 Undo 정보는 변경되기 전 데이터를 가지게 된다. 이러한 Undo 정보는 여러 가지 상황에 맞춰서 적절한 시점에 삭제가 되어야 하는데 이 작업을 Main thread가 처리하며 이 작업을 Purge라고도 부릅니다)가 구동되지 못하도록 합니다. 만일 퍼지 연산(purge operation)이 진행되는 동안 크래시가 발생한다면, 이 복구 값은 퍼지 연산이 실행되는 것을 막으며 MySQL은 시작시킬 수 있습니다.
※ Undo 정보는 InnoDB의 시스템 테이블 스페이스에 관리되기 때문에, 이 경우에는 전체 데이터베이스를 덤프 받은 후 다시 MySQL 서버를 구성해야 합니다.
 
 
 
3 ( SRV_FORCE_NO_TRX_UNDO ) 
  • mysql 종료하던 시점에 진행중인 트랙잭션이 있다면, mysql 단순히 그 연결을 끊는다. 다시 실행 후 innodb엔진이 롤백을 실행하는데 데이터가 손상된경우 롤백을 실행할 수 없기 때문에 이경우 사용되는 복구모드입니다.
  • 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 ) 
  • INSERT, UPDATE, DELETE 연산자를 실행하지 않도록 한다. 테이블 통계값을 계산하지 않도록 한다.
  • 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 ) 
  • 데이터베이스를 시작할 때 UNDO LOG를 검사하지 않는다. InnoDB는 완벽하지 않은 트랜젝션도 실행된 것으로 다루게 된다.
  • 복구 모드 3 ( SRV_FORCE_NO_TRX_UNDO )의 처리와 비슷하며, 이 모드에서는 Undo 로그를 완전히 무시하고 완전히 종료되지 않은 트랜잭션(COMMIT/ROLLBACK되지 않은)을 모두 COMMIT된 것으로 처리해 버린다. 
※ 이 모드에서는 Undo 로그를 전혀 참조하지 않는 형태로 강제 복구 시킨다. 
 
 
 
6 ( SRV_FORCE_NO_LOG_REDO ) 
  • mysql이 재시작전 가장 뒤에 발생한 체크포인트 이후 모든 트랜젝션을 버리고 복구시키는 모드이다 복구 연결에서 로그 롤-포워드(roll-forward)를 실행하지 않고 강제복구한다.
  • 당연히 Redo 로그를 참조하지 않으므로 Roll forward라는 작업도 하지 않고 강제 복구시키게 된다. Redo 로그가 손상된 경우 이 모드로 강제 복구가 가능하다.당연히 Redo 로그를 참조하지 않으므로 Roll forward라는 작업도 하지 않고 강제 복구시키게 된다. 
※ Redo 로그가 손상된 경우 이 모드로 강제 복구가 가능하다.
 
 
 
 
 
 
복구 진행 시 작업 진행 절차
 
1. recovery 옵션을 my.cnf 파일에 넣고, mysql DB를 시작합니다.
# vi /etc/my.cnf
innodb_force_recovery = 1​
 
 
 
2. mysql기동 후 정상적으로 실행이 되었을 때, DB를 dump 뜹니다.
[root@master ~]# mysqldump -uroot -proot --routines --triggers --events --single-transaction [db이름] > kim.sql​
 
 
 
3. mysql정지 후 my.cnf 파일에서 recovery 옵션을 뺀 뒤, 다시 mysql 데몬을 시작해줍니다.
# vi /etc/my.cnf
#innodb_force_recovery = 1​

 

4. 덤프파일 다시 import해줍니다.

## 복구 하고자 하는 database 날려주고 다시 빈 database 생성 => 이렇게 삭제하면 무서우니 datafile 복사해두는 것이 좋습니다.
mysql> drop database kim;
Query OK, 3 rows affected (0.04 sec)

mysql> create database kim;
Query OK, 1 row affected (0.00 sec)


## 덤프파일 import
[root@master ~]# mysql -uroot -proot kim < kim.sql

 

5. 해당 데이터 확인 후 테이블이 깨져있는경우 recovery 옵션의 설정값을 올려서 진행합니다.

 

※ recovery 옵션 3이상 넘어갔을 때에는, 데이터가 망실될 가능성이 큽니다.
여기서 강제 복구 모드는 그 설정 값이 높아질수록 손실되는 데이터가 많아지기(복구 가능한 데이터가 적어지기) 때문에, 가능한 강제 복구 모드를 낮은 것(1 -> 2 -> 3 -> 4 -> 5 -> 6)부터 시도하는 것이 좋다.
recovery 옵션을 통해 복구한 경우 db를 덤프뜬 다음에, recovery옵션을 지우고 다시 데이터를 넣어주는 것이 좋다.
 
강제 복구를 사용한다고 하더라도, 테이블을 덤프하기 위해 SELECT를 실행하거나, 또는 DROP 또는 CREATE 테이블을 사용할 수가 있다. 만일 주어진 테이블에 롤백이 되는 동안의 크래시의 원인이 된다는 것을 알게 되면, 그 테이블을 드롭 시킨다. 또한, 대형 임포트 (mass import) 또는 ALTER TABLE의 실패로 인해 발생한 장기간의 롤백 (runaway rollback)을 중지 시키기 위해서도 이것을 사용할 수가 있다. 
mysqld 프로세스를 죽이고 innodb_force_recovery를 3으로 설정함으로써 롤백 없이 데이터 베이스를 업데이트 시킨 상태로 가져올 수가 있으며, 그런 다음에는 장기간 롤백의 원인이 된 테이블을 DROP시킨다.
데이터베이스는 innodb_force_recovery에 대해서 논-제로 (non-zero) 값을 사용해야만 한다.
데이터베이스의 안전성을 확보하기 위해서, InnoDB는 innodb_force_recovery가 0보다 큰 값으로 설정되어 있을 때에는 사용자가 INSERT, UPDATE, 또는 DELETE 연산을 하지 못하도록 한다.
 
 
※ 용량큰 테이블 적재중 kill 했는데 rollback이 몇시간동안 발생시 
MySQL 고수님들 의견 :  "process kill 시키고 바로 킬안되더라도 rollback 될 때 건드리지말고 끝날때까지 기다리는게 낫다."

 

 

참고 

http://intomysql.blogspot.com/2010/12/innodb_3017.html

 

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

MyISAM 과 달리 InnoDB 테이블들은 매우 안정적이며 , 왠만해서는 데이터 파일이 깨어지는 경우는 거의 경험하지 못했다 . 하지만 , 데이터 파일이 깨어진다면 어떻게 해야 할까 ?. DBMS 벤더를 불문하

intomysql.blogspot.com