DB

DB 데이터 날라가서 복구 한 썰 풉니다... feat 트랜젝션 로그

25G 2025. 7. 25. 19:20

사건의 발단

급한 개발 및 운영배포는 언제나 화를 불러 일으킨다... 우리 팀은 피해갈 수 있을 줄 알았다... 하지만 개발신께선 그딴건 허용하지 않았다...

사건의 발단은 이렇다.

pm님 께서 운영계획에 필요하니 특정 기능을 금주 화요일까지 배포해야한다는 오더가 들어왔다. 그렇게 FE와 BE가 나눠져 PM, BE, FE로 구성된 우리팀은 빠르게 개발에 착수 했다. 아주 간단한 기능이였다. 기존에 쓰던 Form에서 몇가지 항목이 변경됐고 그에따라 DB스키마와 DTO가 일부 변경됐다. 아주 간단 한 작업 입니다 만은... 너무 급하게 작업을 했을까...

영세한 우리 프로덕트는 따로 스테이징 서버가 없었기도 했고 고객사와 시범운영을 했기 때문에 비용 운영적인 부분은 최소화하기 위해 ec2로만 구성하고 고객사에서 접속하고 테스트 해볼 수 있게 열어 놓은 상태였는데 (실제 고객사의 업무 데이터도 라이브하게 들어가 있었음) 중요한 테이블의 특정 컬럼이 위 업데이트이후 해당 테이블의 수정 작업을 하면 위 부분에서 수정한 DTO의 특정 컬럼의 데이터가 null로 BE에 전송돼서 운영데이터의 특정 컬럼의 데이터가 하나씩 null값이 들어가고 있었다. 급하게 하는 프로젝트기도하고 개발 요구사항이 너무 물밀듯이 내려와서 사실 최소한의 방어책정도만 해서 운영중이였기때문에 나에게 있는건... 매일 자정에 쉘 스크립트로 백업하는 s3에 있는 덤프파일들 뿐...이였다.

트랜잭션 로그를 보지 않으면 뭐가 어떻게 변경됐는지 정확하게 추적하기 힘든 상황이였다.

트랜젝션 로그란?

   
목적 장애 복구, 변경 추적, 레플리케이션, 감사(Audit) 등
기록 대상 DML (INSERT, UPDATE, DELETE), 트랜잭션 시작/커밋/롤백 등
특징 순차적 기록, 고속 쓰기 최적화, 주로 바이너리 형태로 저장됨
대표 용도 장애 복구: 장애 시 로그 기반 복원레플리케이션: 로그 기반 복제백업: point-in-time 복구

MySQL에서 트랜잭션 로그 보기

MySQL에서는 트랜잭션 로그는 바이너리 로그(Binary Log) 라고 불립니다.

1. 로그 활성화 확인

SHOW VARIABLES LIKE 'log_bin';

2. 바이너리 로그 목록 확인

SHOW BINARY LOGS;

3. 특정 로그 파일 내용 보기

mysqlbinlog binlog.007123

4. 사람이 읽을 수 있게 verbose 출력

mysqlbinlog --base64-output=DECODE-ROWS --verbose binlog.007123

5. 시간 범위로 필터링

mysqlbinlog --start-datetime="2025-07-23 00:00:00" --stop-datetime="2025-07-23 23:59:59" binlog.007123

 

 

대충 위와같은 프로세스가 있다.

그래서 부랴부랴 ec2 디비 서버로 들어가서 docker 컨테이너 내부에 있는 mysqlbinlog를 전부 내 로컬로 다운받았다.

위 내용들을 응용해서 데이터가 사라진 시점부터 지금 까지의 트렌잭션 로그를 전부 뽑아내는데 성공했다!

 

python으로 파싱해서 Temp테이블에 넣어서 변경내역을 쭉 봐보자!

회사 데이터이기 때문에 로그가 어떻게 나왔는지 공개할 순 없지만 대충 이렇게 생겼다

 

### UPDATE `db_name`.`table_name`
### WHERE
###   @1=1
...
### SET
###   @1=1
..
# at ...

위와같은 구조로 update 트렌젝션 로그가 남는것을 보았다!!

이제 python으로 파싱해서 데이터 추적만 하면 데이터를 복구 할 수 있다!

python코드는 db구조가 들어나기도 하고 사실 재사용 할만한 코드도 못되기 때문에 패스!

 

결론적으로 위 와 같은 구조의 로그파일을 파싱하는데에 성공해서 그간의 사용자들의 수정로그를 .sql 파일로 추출 할 수 있었고

해당 테이블과 똑같은 구조의 temp 테이블을 생성해서 DTO 수정과 관련있었던 컬럼에 대해서 원본과 temp테이블이 싱크가 맞지 않으면 변경내역을 따로 사내 문서에 기록하고 수정하도록 해서 오늘 이슈는 어째어째 마무리가 됐다...

적다보니 내용이 짧은데 진짜 개고생했다..

 

범인 찾기를 해야할까?

이걸 FE 잘못이야!!라고 하는 순간 팀워크와 모든 앞으로의 개발에 긴장감이 고조되어 성장하는 개발팀이 되기는 힘들것이다. 사실 중요한 포인트는 애초에 이런 일이 발생한 것을 방지하기 위한 방법은 이미 많이 있고 알고있었다. 하지만 비즈니스 상황, 비용, 개발 일정 등 많은 병목들이 겹쳐서 미연에 방지 하지 못한 개발팀 전체의 잘못이다. 그렇기 때문에 회사에서 누구도 실수한 팀원의 잘못을 탓하지 않고 오히려 이제는 프로덕트가 좀 크고 있고, 실 사용자들도 늘어나고 있으니 이런일이 다시는 생기지 않게 대첵을 마련하고 프로세스를 개선하고, 시스템을 개선해야할 때가 왔다고 판단하고 앞으로 나아갈 고민들을 하며 이번 사건에 대한 개발팀 회고일정을 잡았다.