문제상황
2025년 1월 16일, 머리에 잊을 수 없는 날이 하나 더 새겨지게 된 것 같습니다.
당일 아침 7시 42분 출근을 하려다가 서버에 문제가 없나? 싶어서 사이트를 새로고침해봤는데 connection refused 문구를 마주하게 됩니다
그 당시에는 대수롭지 않게 생각하여 db에 문제가 있나? docker가 꺼졌나? 하고 가벼운 마음으로 둘러보았는데 docker에 exec를 하려고 하니 input/output error라는 짧은 에러를 확인했습니다.
뭔가 이상하다 싶어서 자세를 고쳐 앉고 확인해보니 docker 컨테이너들이 있는 /dev/sdc 디스크에서 ls조차 되지 않는 사실을 확인합니다
디스크가 맛이 간거죠.
이 디스크 문제는 단순 디스크 문제가 아니고 여러 문제를 안고 있었는데..
그전에 간단히 싴갤러스 백업 체계에 대해 기술합니다.
먼저 싴갤러스는 2017년 구축한 docker 기반의 db 컨테이너로 (no volume set) 운영하고 있습니다.
원래는 host에서 db를 돌리고 있었는데 싴갤러스 - 무중단(을 흉내내는) DB백업 시스템 구축 을 계기로 docker로 운영하고 있었습니다.
정리하면 DB 운영과 백업 체계는 다음과 같습니다
1. mysql docker container 운영
2. mysql replication을 수행하는 또 하나의 docker container 운영
3. n시간마다 replication 컨테이너를 이미지화하여 백업
4. 오전 6시부터 7시까지 mysqldump를 이용한 fulldump 수행. 압축하여 저장. output은 /dev/sdb 에 저장됨
위 시나리오대로 계속 동작했다면 참 이상적일테지만..
얼마전부터 replication과 컨테이너 백업이 중단되어 있었습니다.
싴갤러스 DB 컨테이너가 너무 커진게 문제였습니다. db 컨테이너는 180기가정도 되는데 싴갤러스 서버는 2015년형 물리 서버입니다.
당시 서비스를 함에 있어서 테라단위의 스토리지는 지나친 사치였고(2019년이나 되서야 싴갤러스 DB 크기가 20GB 언저리가 됩니다) 스토리지 가격도 비쌌기에 이런일을 예상하고 테라단위 하드를 사용할 수 는 없었습니다. 그래도 docker 운영은 필요하다 생각하여 2017년에 512GB를 증설하였습니다.
서버에 구성된 스토리지는 다음과 같습니다.
/dev/sda 220GB
/dev/sdb 235GB
/dev/sdc 512GB
처음에 docker 컨테이너가 작을때는 4시간단위로 이미지를 커밋해서 보관하는것 까지 가능했습니다. 그런데 202X년에 들어오면서 db컨테이너는 너무나 거대해졌고, 컨테이너 하나를 더 복제해 운영하는것은 물론 컨테이너를 이미지화 해서 백업하는것 조차 버거운 상황이 되었습니다
결국, fulldump 백업으로만 백업을 운영하는것으로 정하고 컨테이너의 백업은 중단합니다.
그렇게 별 문제없이 시간이 흘렀습니다. DB는 계속 커져 갔습니다
fulldump는 /dev/sdb에 저장이 되었으나, 용량문제로 어느 시점부터는 시간이 많이 지난 파일은 삭제되게 설정했습니다.
그럼에도 어느순간엔 /dev/sdb 역시 거의 가득차게 되었고 파일 백업 스토리지를 수동으로 스위치 하기로 결정합니다.
이 부분에 대해서는..
파일이 저장되는 스토리지 스위치는 거의 몇주에서 한달정도의 텀을 가지기때문에 자동화 할 필요가 없다 생각했고,
파일을 왜이렇게 많이 유지해야 하냐는 질문에는 mysqldump가 항상 완벽한 결과로 성공하지 않기때문에, 최대한 여러개의 파일을 확보하기 위해 n일만큼을 백업하는것입니다
정리하면, 문제가 벌어진 시점쯤에는 /dev/sdc에 fulldump를 수행하고 있었고, 저는 정확한 날짜는 기억나지 않지만 2월부터 /dev/sdb에 fulldump를 저장시키기 위해, 1월의 어떤날에 /dev/sdb에 있는 "모든" 백업파일을 모두 정리(삭제)한 상태였습니다. 새로 생성된 fulldump는 /dev/sdc에만 있었죠.
여기까지가 문제가 벌어진 직전의 상황이었습니다.
즉 디스크가 터짐으로서 싴갤러스는 순간적으로 모든 DB 및 스킴이 전소하는 상황을 마주하게 됩니다....
대응
평일 아침에 벌어진 일이어서 출근을 해야했습니다. 머리가 복잡했죠제일 처음엔 디스크가 맛이갔단 사실을 부정했습니다. 일반적인 에러가 아닐것이다..
애써 부정하며 SMART를 조회해보니 failed 가 나와서 디스크에 문제가 있단걸 확인했습니다..
fsck를 통해 디스크를 바로 복구 시도 해도 되었겠으나, fsck시에는 디스크의 완전한 복구를 보장할 수 없습니다.
따라서 fsck는 최대한 나중에 실행하는것으로 하고 ddrescue 를 통해 복구를 시도해보았습니다.
그런데 단 1바이트 조차 복구가 되지 않았고.. retry 옵션을 3으로 줬음에도 한번도 성공하지 못했습니다.
상기 복구를 돌려놓은 상태에서 /dev/sdb에 저장되었던 full dump를 복구해보자고 접근했습니다. photorec를 받아서 삭제된 덤프파일들의 복구를 시도했고 몇몇 파일의 복구를 성공했습니다.
10여개정도의 gz파일을 얻는데는 성공했습니다만 invalid format에러가 발생하며 압축해제에는 실패했습니다. 사실상 거의 마지막 수단이었기때문에 gzrt를 이용해서 압축파일을 복구하기 시작했는데, 복구된 파일을 한참걸려 열어보았더니 8/10은 깨져있었습니다..
- 기본 파일의 용량도 너무 거대해서 복구도 오래걸리고 압축해제도 오래걸려서 진짜 다시는 안하고 싶은 경험입니다
여기까지 했을때 거의 오후 두시쯤이었고, 더 이상 해볼 수 있는게 하나도 남지 않았습니다
하나 빼고 말이죠..
싴갤러스의 서버는 분당 KT IDC에 코로케이션으로 관리되고 있습니다.
관리업체에 연락을 드려 상황이 이러하니, 서버에서 디스크를 탈착 후에 다른 PC에서 인식되는지 확인을 요청드렸습니다.
이때쯤엔 소프트웨어 문제라기보단 하드웨어 이슈 (커텍터 연결 불량 등..) 에 걸어보았던 것 같습니다.
업체에서는 우분투 PC가 없어서 세팅을 해서 봐주시겠다고 하더군요. 상황이 안좋아보여서 하시는 업무가 아니어도 해주신 것 같습니다
하지만..
관리 업체에서 (원래하지 않는 업무지만) 테스트결과 다른 PC에서도 인식되지 않는다는 말을 듣고,, 디스크를 다시 서버로 연결을 부탁드렸습니다. 그리고 서버가 다시 기동되었는데...
/dev/sdc가 멀쩡히 연결이 된 상태로 부팅되었습니다...
진짜 무슨 이런 경우가 다 있나 싶었습니다. 마냥 그냥 기뻐할수도 없는게, 문제의 원인을 모르니까 이 상태로 서비스를 돌려도 되는지 머리에 잔뜩 물음표가 새겨졌습니다. 말씀드렸지만 싴갤러스의 DB는 전소한 상황이고 복구(?) 된 디스크에 모든걸 걸어야되는 상황인것이죠. 따라서 당장 서비스를 돌리는건 포기하고 해당 디스크의 백업을 준비하기 시작했습니다.
백업을 위해서 관리센터에 문의했으나 그런 업무는 하지 않으신다고 하여, 21시부터 다음날 (금요일) IDC 방문하려고 준비를 시작했습니다.
백업 플랜은 심플했습니다.
clonezila 를 이용하여 서버를 재시작하고, 외장하드로 핫 부트한 이후, /dev/sdc의 디스크 섹터를 새로운 외장하드로 복사하는것이죠.
저는 가진 외장하드가 없어서, 조금이라도 시간을 줄이려고 즉시 쿠팡으로 구매했습니다 (새벽에 도착)
그런데 현실적인 문제가 또 발생했는데,
* IDC방문은 전일 신청해야 함
- 방문시간은 09시부터 18시까지로 한정되며 평일만 가능
- 21시에 요청은 불가능 (당직자가 해당 업무를 처리할 수 없음)
따라서..
다음날인 금요일 09시에 방문 신청을 한다고 해도 그 다음날은 토요일이라 방문할 수 없습니다. 그 다음날도 일요일이라 방문할 수 없습니다..
그럼 월요일인데 월요일에 방문하면 서버는 이미 거의 4일을 멈춰있는 상태가 되고 저는 연차를 소모해야하며.. 생업에도 지장이 생기죠..
결국 이 대목에서 원격 백업을 진행하기로 합니다. 맛이 가면 하드 뜯어서 업체에 맡기자는 마음으로 할 수 있는걸 해보자는.. 도박이었는데요.
제 컴퓨터는 윈도우 컴퓨터라서 일반적인 ftp로 파일을 옮길 경우 symbolic link등이 문제가 될 수 있어 윈도우에 wsl을 세팅, 이어서 openssh 클라이언트를 설치하고, rsync로 /dev/sdc의 파일을 모두 옮기기로 결정합니다. /dev/sdc의 용량은 310GB정도였습니다
그전에 SMART 도 멀쩡한것을 확인하고, testdisk를 이용해 20분짜리 긴 테스트도 진행했으나 OK가 나왔습니다.
그래도 만일에 대한 불상사를 위해 쿠팡으로 받은 외장하드에 clonezila 이미지를 설치해 핫 부트 할 수 있도록 준비했습니다.
엔터 한번 남은 상황에 고민하다가 날짜가 바뀐 0시 20분경쯤 rsync 작업을 시작했습니다. 계산상 6시간정도가 걸리더군요.
날밤을 깔순없어서 결국 새벽에 한번씩 일어나서 살펴보는걸로 결정, 2시, 4시쯤 일어나서 살폈는데 잘 진행이 되고 있어서 다행이었습니다
그리고 아침에 모든 파일이 백업된것을 확인했습니다.정확히는 166KB정도가 옮겨지지 않았는데 영향은 미미할거라 생각했고,
fsck 를 통해 디스크 전체 복구했습니다 (하나도 문제가 없다고 나와서 허탈했습니다...)
이후, docker 서비스를 올려서 싴갤러스 서비스가 제대로 기동되는것을 확인했습니다.
TOBE
서버신이 도와 겨우 복구(?)가 되었기에 이런일이 벌어지지 않도록 백업플랜을 다시 설정해야했습니다.
싴갤러스는 수입이 적지만, DB가 큰 프로젝트입니다. 이정도 규모 프로젝트를 외부에 업로드한다던지 하면..(사실 거대 서비스에 비해 크지도 않습니다만) 그 즉시 손해가 발생합니다. 따라서 자력으로 해결해야하는 제약이 있습니다.
용량없어서 중단하는 그런 불상사는 없도록 해야겠으니 가진 재원에서 최대한의 퍼포먼스를 내야합니다
먼저 IDC 방문을 위해 구매했던 외장하드를 사용하기로 합니다. 이미 파일까지 써버려서 환불할 수 없는 상태였거든요
저희집 공유기에는 USB포트가 있어 외장하드를 연결하면 FTP 서버 처럼 쓸 수 있단걸 깨닫고는, ddns를 설정해주고 외부 환경에서 파일을 업로드 하고 지울수 있는 스크립트를 생성하고 테스트 완료했습니다. 간단히 1TB 짜리 FTP 서버가 구성된 셈입니다
그 다음은 /dev/sdb에 저장되던 fulldump를 /dev/sda로 돌렸습니다. 메인 디스크이지만 잠깐 머물다 간다는 느낌으로 서버에는 한두개정도만 남기고, FTP 서버로 전송하도록 했습니다.
그 이후, mysql replication을 다시 잡아주기로 했습니다. 컨테이너는 백업을 위해 볼륨을 다시 설정할 필요가 있었으므로 db 이미지를 다시 받고, 컨테이너도 볼륨을 /dev/sdb를 바라보게 하여 도커 컨테이너를 새로 만들었습니다. 이로서 primary는 /dev/sdc에, 백업용 replication 컨테이너는 /dev/sdb에서 돌게함으로서 디스크를 이중으로 쓰게 설정해서 이번과 같은 디스크 폭발 사고에도 대응할 수 있게 했습니다
그 이후에는 mysql replication을 다시 먹이고 master의 데이터를 밀어넣기 시작했습니다.
데이터가 크다보니 이 과정도 너무나 오래걸렸습니다....
아무튼, 그렇게 백업용 replication 컨테이너를 만들었고, 마무리 했습니다.
기존에는 다음과 같이 백업을 진행했습니다.
/dev/sdc -> fulldump / main db container / backup db container(stopped)
사용하는 디스크는 다음과 같이 변경되었습니다..
/dev/sda -> fulldump + backup ftp server
/dev/sdb -> backup db container
/dev/sdc -> main db container
느낀점
장애를 해결하고 백업 플랜을 세우면서 싴갤러스라는 서비스에 많이 무심했던 것 같습니다. 그게 사실이고..open api 도 나오면서 사이트 정체성도 좀 무너지는것 같고, 홈페이지 디자인과 기능이 옛날 옛적에 정체되어있는것도 알고 있습니다. 안타깝지만 저도 어렸을적 어른들이 비겁한 변명을 한다고 생각했던, '바빠서 그렇다' 는 말을 하게 되는것이 참 묘한 감정이 들게 합니다.
생업이라는 변명에 숨어 안일하게 살았던 것 같습니다.
당분간은 계획한 백업플랜이 제대로 동작하는지 확인하고, 여유가 생기면 싴갤러스 기능을 개선하도록 노력하겠습니다.
서비스 이용에 불편끼쳐드려 죄송하고 열심히 하겠습니다.