침입 조사에서 백업이 유용했던 일이 있어서 그 뒤로 백업을 제대로 해 두기로 했다. 원래도 crontab 에서 매일 밤 mysqldump 가 돌고는 있었는데 다시 보니 걸리는 것이 둘 있었다.
Table of contents
Open Table of contents
같은 서버에만 있었다
덤프 파일이 같은 서버의 다른 폴더에 쌓이고 있었다.
매일 밤 DB 덤프
같은 서버의 다른 폴더
폴더가 다르니 나눠 둔 것 같지만 디스크가 죽으면 둘 다 죽고 침입당하면 둘 다 당한다. 원본과 사본이 같은 운명을 공유하면 사본이 아니다.
두 번째는 복구를 한 번도 해 본 적이 없다는 것이었다. 확인한 것은 파일이 생긴다는 사실뿐이었다.
파일이 있는 것과 복구되는 것이 다르다는 것이 이번 작업의 핵심이었다. 파일이 있다는 것은 뭔가 만들어졌다는 뜻이고 복구된다는 것은 그것으로 되살릴 수 있다는 뜻이다. 중간에 깨진 파일은 앞의 조건만 만족한다.
그래서 시험용 서버에 며칠치를 실제로 넣어 봤다. CREATE DATABASE 로 빈 것을 만들고 mysql < dump.sql 로 부어 보는 것인데 하나가 중간에서 멈췄다.
검증 — 잘린 파일을 걸러 냈다
들어가지 않은 파일의 크기를 du 로 다른 날과 비교하니 훨씬 작았다. 중간에 끊긴 것이다.
그날 로그를 보니 덤프를 쓰는 도중에 디스크가 찼다. 문제는 그렇게 중단돼도 mysqldump 가 쓰던 파일은 남는다는 것이었다. 잘린 채로 남아서 겉으로는 정상으로 보인다.
덤프 뒤에 확인을 두 가지 넣었다.
크기가 최소값보다 큰가
tail -1 이 정상 종료 표시인가
뒤쪽이 확실했다. mysqldump 는 다 쓰고 나서 마지막에 -- Dump completed on 으로 시작하는 주석 한 줄을 붙인다. 중간에 끊기면 그 줄이 없다. 크기만 보면 그날 데이터가 적었던 것인지 잘린 것인지 애매한 경우가 있는데 이건 명확하다.
다만 이 검사에는 전제가 하나 있다. --skip-comments 를 주면 그 줄 자체가 안 나온다. 옵션을 누가 건드리면 검사가 조용히 아무것도 안 보는 상태가 된다. 그래서 덤프 명령과 검사를 같은 스크립트에 두고 옵션을 거기서만 정하게 했다.
다른 곳으로 옮기고 대조했다
첫 번째 문제도 고쳤다. 서버에서 덤프를 뜨고 그것을 다른 곳으로 보내 두 곳에 있게 했다.
그런데 여기도 같은 함정이 있었다. rsync 가 0 으로 끝났다는 것이 파일이 제대로 도착했다는 뜻은 아니다. 보낸 것과 도착한 것을 대조해야 한다.
보낸 쪽에서 계산
받은 쪽에서 계산
비교
크기를 비교하고 양쪽에서 sha256sum 을 계산해 맞췄다. 크기만 보면 내용이 달라도 같은 값이 나올 수 있는데 해시는 내용이 다르면 다르게 나온다. 대조는 지정한 방식과 다른 방식으로 되읽는 것이어야 뜻이 있다.
보관과 삭제와 정기 시험
두 곳에 쌓이니 공간이 문제가 됐다. 보관 기간을 세 단으로 정했다.
최근 것 며칠치
주 단위 몇 주
월 단위 몇 달
가까운 것은 촘촘하게 두고 먼 것은 드물게 둔다. 어제 문제를 조사할 때는 어제 것이 필요하고 몇 달 전 상태를 볼 때는 그 무렵 것 하나면 되기 때문이다. 필요한 정도가 다르니 간격도 달라야 했다.
지우는 스크립트를 넣을 때는 잘못 지우면 백업이 없어진다는 것이 걸렸다. find -mtime 으로 대상을 고르되 처음에는 rm 없이 목록만 내게 했다. 며칠 보면서 목록이 맞는 것을 확인한 뒤에 실제 삭제를 켰다.
마지막으로 복구 시험을 한 달에 한 번 아무 날짜나 골라서 하도록 정기로 만들었다. 한 번 해 보고 끝내면 그 뒤에 깨져도 모른다.
시험할 때 무엇을 보면 통과인지도 함께 적었다.
넣는 중 오류가 없나
주요 테이블의 행 수가 그럴듯한가
최근 데이터가 들어 있나
행 수는 COUNT(*) 로 보고 최근 데이터는 MAX(reg_date) 가 그 덤프 날짜에 가까운지로 본다. 복구해 봤다는 말만으로는 부족하고 넣고 나서 무엇을 볼지가 있어야 했다.
정리
- 백업이 같은 서버에만 있으면 원본과 같이 없어진다
- 파일이 있는 것과 복구되는 것은 다르다
- 디스크가 차면 잘린 파일이 남는다. 겉보기에는 정상이다
tail -1의-- Dump completed on으로 잘림을 확인한다--skip-comments를 주면 그 줄이 없어져 검사가 무력해진다rsync의 종료 코드 0 은 도착의 증거가 아니다 —sha256sum으로 대조한다- 보관은 최근·주·월 세 단으로 두고 먼 것일수록 드물게 남긴다
find -mtime삭제는rm없이 목록만 먼저 내 본다- 복구 시험 통과 기준은 오류 없음과
COUNT(*)와MAX(reg_date)셋이다