mlflow 의 backend store 로 mysql server를 사용 중 artifact 저장 path 가 바뀌어 이를 수정 하는 도중 

문제가 발생해 이를 해결한 과정을 정리한다. 

같은 상황에 처하게 될지 모를 미래의 나 자신과 비슷 한 상황에 처할지 모를 누군가에게 도움이 되길 바란다. 

 

환경 정보:

PC1 host os: ubuntu 2004

PC1 docker version:

PC1 docker compose version:

PC1 mysql server image: mysql/mysql-server:8.0.28

PC1 mlflow version:1.24.0

 

PC2 host os: ubutu 18.04

PC2 docker version:

PC2 docker compose version: 

PC2 mysql server image: mysql/mysql-server:8.0.28

PC2 mlflow version: 1.24.0

 

이슈 발생 상황:

이슈 발생 원인은 복합적이다.

복잡할 수 있지만 정확하게 정리하고 기록하기 위해 상황을 설명한다. 

상황은 아래와 같다.  

 

나는 Fig 1. (A) 와 같은 pc1(내 주사용 pc)에 mlflow tracking server, mysql server를 운영 중이었다.

mlflow tracking server 와 mysql server는 각각 docker container 로 instance화해 운영하고 mysql은 mlflow의 backend store로 NAS에 있는 특정 directory를 artifact uri로 사용하고 있었다. 

 

그러던 중 놀고 있는 pc2를 발견하고 pc2에 mlflow tracking server와 mysql server를 운영 하면 내 주pc 인 pc1은 한결 가볍게(필요할때 재부팅 등) 사용 할 수 있기에 Fig 1. (B) 처럼 pc2로 서버를 운영 하고 pc1은 학습에 사용 하기로 하고 서버 이관(?)을 실행에 옮겼다.

Fig 1 시스탬 구조도

그리고 나서 artifact uri path를 변경해야 하는 상황이 발생했다.(누가 옮겨 달라고 부탁해서...)

기존 실험과 관련된 checkpoint 등의 artifact도 변경된 artifact uri path 로 옮기고 mlflow ui를 실행하니 artifact가 하나도 표시가 안된다. 그래서 mysql에 등록된 기존 experiment와 runs의 artifact uri path를 변경된 경로로 바꾸려고 mysql client 로 접속해 update 쿼리를 실행했다. lifecycle_stage가 'deleted'인 몇몇 run이 보기길래 이것도 지웠다.

 

지우고 나니 잠시 뒤 부터 mysql server crash되면서 무한 restart 되기 시작했다. docker-compose ps 로 보니 mysql server status 가 restarting 만 계속 뜬다. 

 

아래 명령어로 로그를 확인 했다.

docker logs mysql_server

Fig 2 와 같은 로그가 뜬다. 

Fig 2. mysql server error log

원인을 찾기 위해 Fig 2 error log를 분석하던 도중 'there may be corruption in the InnoDB tablespace.' 라는 문구가 눈에 띄었고 검색을 하며 찾던 중 Fig 3 와 같은 단서를 찾았다. 

 

Fig 3. error about multiple mysql server

Fig 1.에서 PC1에서 돌던 서버를 PC2로 옮기는 과정에서 혹시 PC1의 mysql 서버를 다운 시키지 않았나? 라는 생각이 들어 확인해 보니 아직 돌고 있다. 하나의 물리적인 database 파일에 대해 mysql server 두개가 접근 및 수정을 하고 있었던 것이다. 즉 Fig 4와 같이 mysql 서버가 동작 하고 있었던 것이다. 

Fig 4. issue를 발생 시킨 원인으로 추정되는 mysql 서버 운영 형태

locking이 disable된 건지는 내가 dbms 전문가가 아닌지 모르겠으나 가장 의심되는 상황이었다. 

 

 

해결 방법:

해결방법은 Fig 1 (B)에 있는 PC2에서 실행한 것이다. PC2의 os,툴, 프로그램 등의 버전은 Env info의 PC2 XX 를 참조하기 바란다.

 

복구를 시도했지만 db 전문가가 아니어서 인지 실패 했다.

실패 한 방법을 간단히만 언급하자면 my.cnf에 innodb_force_recovery=6 을 추가해 복구 모드로 mysql server 실행 후 복구 시도 했지만 레벨 6에서는 table drop 및 import 가 안되어 실패 했다. 

 

내 목적은 어디까지나 mlflow로 실험 및 모델 관리이므로 목적을 가장 쉽게 달성 할수 있는 방법으로 

crash 된 database 백업 후 새로운 database를 구축 하고 백업 본을 임포트 해서사용 하기로 했다. 

(이 방법은 database가 크면 사용 하기 힘들거 같기도 하다.. 나의 경우엔 다행히 database 가 작았다.)

 

절차는 아래와 같다. 

 

step 1. mysql server를 recovery mode로 실행하기 위해 /etc/my.cnf 파일 수정. 나의 경우 mysql 공식 docker image를 사용 하고 있었는데 container 내부에서 vi, vim, nano등 text에디터가 설치된 흔적을 찾지 못해 my.cnf 파일을 host os로 복사 후 수정해 사용했다. 

 

docker container side: 

cp /etc/my.cnf /backup/space
# /backup/space는 container 실행시 마운트한 host 의 home directory 이다.

host side:

vim /home/my.cnf

[mysqld]
innodb_force_recovery=6

 

step 2. 수정된 my.cnf를 이용해 mysql server를 실행하기 위해 mysql server container 재 실행

docker run -it --name mysql_crashed_server -e MYSQL_DATABASE=ObjectDetections -e MYSQL_USER=mysql -e MYSQL_PASSWORD=mysql -e MYSQL_ROOT_PASSWORD=chmod777 --user mysql:mysql -v /home/user/my.cnf:/etc/my.cnf -v /home/user:/backup/space -v /nas/mysql_db:/var/lib/mysql mysql/mysql-server:8.0.28 bash

#contaner 내부에서
$ mysqldump -u mysql -p ObjectDetections > backup_objectdetection_database.sql

 

step 3.  step 2번에서 실행 시킨 docker container stop 및 삭제

docker stop mysql_crashed_server && docker image mysql/mysql-server:8.0.28

 삭제 하는 이유는 mysql docker 이미지로 mysql server를 실행하면 최초 실행에만 /var/lib/mysql 에 database관리를 위한 설정 파일들을 세팅 하기 때문이다. 따라서 기존 사용 하던 docker 이미지 자체를 지우고 새로 pull 해야 한다. 

 

step 4. 아래 그림 Fig 5와 같이 새로운 database 를 구축할 mysql_new 디렉토리를 생성.

 

mkdir /nas/mysql_new

 

Fig 5. 새 database dir 생성 및 마운트

step 5. mysql server 실행

이걸 할수 있는 방법은 여러가지가 있지만 나는 docker compose를 이용해 server들을 관리하므로 그냥 내 경우로 정리한다. 

$ docker compose up -d

아래는 내가 사용 하는 docker-compose 파일의 내용 중 일부 이다. 

version: '3.8'
services:
	db: 
    	image:mysql/mysql-server:8.0.28
        container_name: mysql_server
        expose: 
        	- ${MYSQL_SERVICE_PORT}
        ports:
        	- 0.0.0.0:13306:3306
 	networks:
        	- backend
        	- frontend
        command: --default-authentication-plugin=mysql_native_password
        restart: always
        environment:
        	- MYSQL_DATABASE=${MYSQL_DATABASE}
            - MYSQL_USER=${MYSQL_USER}
            - MYSQL_PASSWORD=${MYSQL_PASSWORD}
            - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
        user: mysql:mysql
        stdin_open: true
        tty: true
        volumes:
            - type: bind
              source: /nas/mysql_new # 새로 데이터베이스를 구축할 디렉터리로 위치가 바뀌었다. crash된 database의 위치는 /nas/mysql_db 이다.
              target: /var/lib/mysql
              read_only: false
            - type: bind
              source: /home/mysql
              target: /backup/space

 

step 6. step 5까지 실행 하면 mysql server 가 필요한 설정 파일들을 /nas/mysql_new(container 내부 경로 /var/lib/mysql) 에 생성 했을 것이다. 이제 새로 생성된 database에 step 2에서 백업한 기존 실험 기록들을 restore 해보자.

 

아래 명령으로 mysql server 가 실행되고 있는 container 에 연결해 mysql client 를 실행 하자. 

#host 의 terminal 에서
host$ docker exec -it mlsql_server bash

bash$ mysql -u mysql -p
passwd:

패스워드를 입력하고 myql client cli가 실행 되면 아래 명령을 입력한다. 

mysql> use ObjectDetections; #내 database 이름 이다. 복구하고자 하는 database 이름으로 대체 하면 된다.
mysql> set autocommit=0; #큰 데이터 파일을 위해 속도 증가를 위해 오토 커밋을 끄는 과정인데 생략해도 된다.
# restore backup database. step 2에서 백업했던 database 파일이다. 나의 경우 이게 /backup/space/에 위치한다. 
mysql> source /backup/space/backup_objectdetection_database.sql;

 

step 7. 이제 mysql 과 mlflow tracking 서버를 모두 시작(또는 재시작) 하면 된다. 무한 restart 되던 mysql server 가 정상적으로 start 되고 mlflow ui web 화면을 통해 복원한 실험 결과도 확인할 수 있다. 

 

- 끝 -

+ Recent posts