
서버 이중화했는데 장애 때 안 넘어가는 이유와 점검법
대기 서버의 복제 로그는 줄마다 같은 말로 끝났습니다. "OK".
주 서버에서 데이터를 내보내는 쪽 로그도, 그걸 받아 대기 서버에 붓는 쪽 로그도 한 줄도 빠짐없이 OK였습니다.
그런데 같은 시각 대기 서버의 앱은 생성 단계에서 멈춘 채 기동조차 못 하고 있었습니다. 주 서버가 꺼졌다면 넘어갈 곳이 없었던 셈입니다.
제가 만들어 자체 서버로 돌리는 사내 그룹웨어의 대기 서버 이야기입니다. "대기 서버가 있으니 괜찮다"고 믿었던 구성을 층마다 다시 뜯어봤습니다.
매일 OK였던 대기 서버
구성은 단순했습니다. 주 서버와 대기 서버는 서로 다른 건물에 있고 인터넷으로만 이어집니다.
주 서버가 주기적으로 DB와 첨부파일을 암호화해 외부 저장소에 올립니다. 대기 서버는 그걸 받아 자기 DB에 복원합니다.
주 서버가 죽으면 대기 서버의 앱을 켜고 접속 경로를 그쪽으로 돌립니다. 이 전환을 페일오버라고 부릅니다.
구축하던 날 주 서버의 외부 연결을 실제로 끊고 드릴을 했습니다. 첫 시도는 접속 자격 파일의 권한 문제로 실패했고, 고친 뒤 두 번째에 20~30초 만에 넘어갔습니다.
그 뒤 4주가 지나 "회선이 끊기면 정말 무중단이냐"는 질문으로 구성을 다시 봤습니다. 무중단이 아니었고, 페일오버 자체가 불가능한 상태였습니다.
대기 앱은 왜 못 떴나
대기 앱 컨테이너는 'created' 상태에서 한 발짝도 못 나가고 있었습니다. 원인은 첨부파일 폴더를 연결하는 마운트 경로 한 줄이었습니다.
처음 대기 앱을 만들 때는 서버에서 직접 스크립트를 돌렸고 경로가 맞았습니다. 드릴을 통과한 것도 이 상태였습니다.
이후 앱 이미지가 갱신될 때마다 복제 담당 자동화가 대기 앱을 지우고 다시 만들게 해 두었습니다. 이 자동화는 별도 컨테이너 안에서 돕니다.
자동화는 자기 컨테이너 안에서 보이는 경로를 적었습니다. 도커는 그 경로를 서버 본체 기준으로 찾으니 없는 폴더가 되고, 생성이 실패한 앱은 멈춘 채 남았습니다.
복제는 정상이었으니 로그는 계속 OK를 찍었습니다. 감시선이 복제만 보고 있어서 승격 쪽 고장은 어디에도 드러나지 않았습니다.
고치는 건 경로 변수 하나로 끝났습니다. 대신 재생성 직후 대기 앱을 실제로 띄워 응답을 확인하는 단계를 붙였습니다. 다시 만드는 일과 떠 보는 일을 한 짝으로 묶었습니다.
제 실수도 남겨 둡니다. 같은 날 진단 도구와 다른 복원 검증을 만들면서 저는 이 경로 실수를 두 번 더 했습니다.
세 번 밟고 나서야 서버 본체 경로를 변수 하나로 통일했습니다. 한 곳을 고칠 때 같은 패턴이 어디 또 있는지 같이 찾아야 했습니다.
첫 줄에서 멈추는 런북
런북에는 페일오버 명령이 한 줄로 적혀 있었습니다. 장애가 나면 이것만 치면 된다는 뜻이었습니다.
그 명령의 첫 단계는 관리자 권한으로 도커를 부르는 것이었습니다. 드릴 때는 비밀번호 없이 됐는데 그 사이 계정 권한이 바뀌어 있었습니다.
스크립트는 비밀번호를 물어볼 수 없게 짜여 있습니다. 런북의 한 줄은 첫 줄에서 실패하는 상태였습니다.
실제 장애였다면 저는 원인을 찾느라 시간을 썼을 겁니다. 그동안 서비스는 계속 죽어 있었을 테고요.
하나가 더 있었습니다. 대기 쪽 접속 경로 설정에 그룹웨어 주소만 있고 외부 고객용 문의 창구 주소가 통째로 빠져 있었습니다.
넘어가는 데 성공했더라도 문의 창구는 404를 냈을 겁니다. 드릴은 그룹웨어 주소 하나로만 했기 때문에 보이지 않았습니다.
데이터 세 벌, 설정 0벌
여기까지 고치고 한 층 더 올라가 봤습니다. 서버가 통째로 사라지면 맨바닥에서 다시 세울 수 있는지 종이 위에서 순서대로 걸어 봤습니다.
데이터는 세 벌이 있었습니다. 그런데 그 데이터를 서비스로 띄우는 설정은 한 벌도 백업되지 않고 있었습니다.
외부 접속 터널의 자격 파일, 리버스 프록시 설정, 39줄짜리 예약 작업표, 웹서버 설정 같은 것들입니다. 터널 자격 파일은 457바이트였습니다.
다 합쳐도 1MB가 안 되는 뭉치가 공개 도메인 전체의 생사를 쥐고 있었습니다.
설정 백업을 새로 만들었습니다. 암호화한 1.04MB 묶음을 서로 다른 두 곳에 보관하고, 주 1회 실제로 복호해 열리는지 검사합니다.
이 스크립트도 첫 판에서 사고를 냈습니다. 프록시 설정 경로를 한 단계 위로 적었는데 목록 기반 백업은 없는 항목을 말없이 건너뛰고 성공을 보고했습니다.
그날 종일 고치던 병을 제 손으로 재현한 셈입니다. 그래서 꼭 있어야 하는 항목을 따로 갈라 하나라도 없으면 백업 전체를 실패로 끝내게 했습니다.
다만 이 순서로 새 장비에 실제로 세워 본 적은 아직 없습니다. 의존 관계를 실측해 짠 순서이고 검증된 절차는 아닙니다.
'만들어졌는가'와 '복원되는가'
점검 범위를 다른 서비스까지 넓혀 보니 백업 감시가 6종 있었습니다. 6종 모두 백업 파일이 만들어졌는지만 보고 있었습니다.
그래서 덤프를 빈 DB에 실제로 부어 보는 복원 리허설을 주 1회 자동으로 돌리게 했습니다. 리허설이 멈추거나 실패하면 감시선이 알려 줍니다.
이 리허설이 '복원되는가'를 보는 유일한 감시선이 됐습니다. 그룹웨어 대기 서버에서 찾은 고장과 다른 서비스까지 넓혀 본 결과를 한 그림에 합치면 이렇습니다.
네 층은 서로 따로 죽을 수 있습니다. 아래층이 초록이어도 위층은 직접 눌러 봐야 압니다.
비밀번호 없이 넘기는 페일오버
권한 문제는 절차를 바꿔서 풀었습니다. 이미 도커를 다룰 권한을 쥔 복제 담당 프로세스에게 승격을 맡겼습니다.
이제 페일오버는 정해진 폴더에 FAILOVER라는 빈 파일 하나를 만드는 일입니다. 복제 담당이 그 파일을 보고 대기 앱을 띄우며 경로를 넘깁니다.
비밀번호도 관리자 화면도 필요 없어서 폰의 SSH 앱으로 한 줄이면 됩니다. 복귀는 FAILBACK 파일이, 승격 중 복제 정지는 FROZEN 파일이 맡습니다.
이 구조는 막다른 길에서 나왔습니다. 저도 대기 서버의 관리자 웹 화면에 로그인하지 못했고, 그 화면을 거치지 않는 길을 찾다 보니 이렇게 됐습니다.
운영 서비스에 영향을 주지 않고 대기 쪽만 띄워 보는 반쪽 드릴 명령도 같이 만들었습니다. 주 1회 자동 드릴은 실패할 때만 알립니다.
데이터 손실 허용 범위도 줄였습니다. 복제 주기를 120초에서 30초로 당겼고 덤프 한 번이 실측 284ms라 부담이 거의 없었습니다.
평시 대기 서버의 복원은 5분쯤 걸려서 늘 조금 뒤처져 있습니다. 그래서 승격 직전에 한 번 더 당겨 오는 동기화를 넣어 손실 범위를 복제 주기 수준으로 내렸습니다.
| 항목 | 점검 전 | 점검 후 |
|---|---|---|
| 데이터 손실 허용 범위 | 2~4분 | 약 1분 |
| 복제 주기 | 120초 | 30초 |
| 회선 단절 감지 | 최대 25시간 | 최대 30분 |
| 페일오버 실행 | 관리자 비밀번호 필요(실패) | 빈 파일 하나 생성 |
| 설정 묶음 사본 | 0벌 | 2곳, 주간 복호 검증 |
회선 단절 감지는 외부 무응답 감시의 주기를 바꾼 결과입니다. 24시간에 유예 1시간이던 설정을 15분에 유예 15분으로 줄였습니다.
주 서버 쪽 감시 장비가 같이 죽는 경우도 따졌습니다. 대기 서버에서 직접 알림을 내보내는 경로를 따로 만들고 실제 발송까지 확인했습니다.
두 곳 동시 운영은 왜 안 했나
점검 중에 이런 질문을 받았습니다. 큰 회사들은 데이터센터 여러 곳을 동시에 돌리지 않느냐는 것이었습니다.
그 구조가 화재에도 버티는 데는 조건이 있습니다. 데이터센터 사이가 1ms 미만으로 가깝고, 노드가 셋 이상이라 과반 판정이 나옵니다.
제 구성은 둘 다 해당하지 않습니다. 두 건물이 인터넷으로 이어져 동기 복제가 불가능하고, 노드가 2개라 한쪽이 끊기면 누가 죽었는지 판정할 수 없습니다.
앱은 순번 ID를 쓰고 있어 양쪽에서 동시에 쓰면 충돌을 풀 방법도 없습니다. 1인 운영으로 감당할 복잡도를 넘는다고 보고 하지 않기로 했습니다.
| 선택지 | 판단 |
|---|---|
| 두 곳 동시 운영 | 과반 판정 불가, 동기 복제 불가로 보류 |
| 대기 서버 + 수동 전환 | 유지, 전환은 파일 트리거로 단순화 |
| 제3 저장소 목격자 판정 | 도입, 지금은 알림만 보내는 시험 운영 |
대신 판정 방식만 빌려 왔습니다. 외부 저장소를 제3의 목격자로 세우고 주 서버가 30초마다 그곳에 현재 시각을 씁니다.
시각이 멈추면 주 서버가 죽었거나 끊긴 것입니다. 시각은 갱신되는데 대기 서버에서만 주 서버가 안 보이면 둘 사이 경로 문제로 보고 넘기지 않습니다.
여기에 외부 주소 무응답을 함께 걸어 두 조건이 모두 맞을 때만 다운으로 판정합니다.
시험 운영 중에 감시기가 정상 서비스를 다운으로 읽은 일이 있었습니다. 감시 요청이 기본 사용자 에이전트로 나가 보안 계층에서 403을 받았고, 200이 아니니 다운이라고 판정한 겁니다.
기준을 "응답이 오면 살아 있다"로 고쳤습니다. 이제 무응답과 5xx만 다운으로 셉니다.
아직 닫지 못한 것
대기 쪽 외부 접속 커넥터는 설정 검사만 통과했습니다. 마지막으로 실제로 띄운 건 구축 날 드릴이고, 그 뒤 설정이 바뀌었습니다.
주 서버가 살아 있을 때 켜면 트래픽이 두 쪽으로 갈라져 일부 사용자가 옛 데이터를 보게 됩니다. 그래서 사용량이 낮은 시간에 짧게 확인할 예정입니다.
인터넷이 끊겼을 때 사내망만으로 쓰는 길도 아직 없습니다. 로그인이 외부 계정 인증 하나라 회선이 끊기면 새 로그인이 막힙니다.
사내 시스템을 자체 서버로 운영한다면 대기 서버가 어느 층까지 증명됐는지부터 확인해 보세요. 제가 만든 그룹웨어의 실제 화면은 그룹웨어 데모에서 볼 수 있습니다.
대기 서버가 정말 뜨는지 확신이 없다면 구성 점검 상담에 서버 대수와 복제 방식을 남겨 주세요. 아래 점검표를 먼저 한 번 돌려 보시면 대화가 빨라집니다.
이중화 4층 점검표
대기 서버가 있다는 사실과 넘어갈 수 있다는 사실은 따로 확인해야 합니다. 아래 순서대로 한 층씩 눌러 보세요.
- 복제가 도는가. 복제 로그의 마지막 성공 시각이 주기 안에 있는지 보세요. 그 로그는 데이터 복사만 증명합니다.
- 복원되는가. 백업을 빈 DB에 실제로 부어 보는 리허설이 주 1회 이상 자동으로 도는지, 실패하면 누가 알림을 받는지 확인하세요.
- 서비스로 뜨는가. 대기 앱이 지금 실제로 기동해 응답하는지 보세요. 배포나 이미지 갱신 뒤에도 다시 확인되는 구조여야 합니다.
- 외부 경로가 전부 넘어가는가. 대기 쪽 라우팅에 고객용 주소까지 다 들어 있는지 양쪽 주소 목록을 나란히 대조하세요.
- 맨바닥에서 다시 세울 설정이 있는가. 터널 자격, 프록시 설정, 예약 작업표가 데이터와 별도로 백업되는지 보세요. 필수 항목이 빠지면 백업이 실패로 끝나야 합니다.
- 페일오버에 사람의 권한 입력이 끼어 있지 않은가. 비밀번호나 관리자 화면 로그인이 필요한 절차는 장애 당일 그 단계에서 멈출 수 있습니다.
- 마지막 드릴은 언제였는가. 통과한 드릴도 권한 변경과 자동 재생성으로 깨집니다. 제 경우 4주 만에 두 곳이 깨져 있었습니다.
이어서 읽기

프로그램 유지보수 비용, 다 만든 뒤 매달 무엇에 돈이 드나
업무 시스템은 다 만든 뒤에도 배포가 저절로 깨지고 백업이 조용히 멈춥니다. 지점 대시보드와 지사 시스템의 실제 운영 기록으로 유지보수비와 서버비가 무엇을 사는지, 견적서와 계약서에서 어떤 줄을 먼저 읽어야 하는지 짚었습니다.

사내 시스템이 갑자기 느려졌을 때, 문의 화면 폴링 한 줄이 범인이었던 사례
로그인에 8~21초가 걸리던 사내 그룹웨어를 진단한 기록입니다. 서버 사양 탓으로 보이던 느림 뒤에는 2.5초마다 도는 쓰기 한 줄과 디스크 점검의 겹침이 있었습니다. 두 번 틀린 측정과 그걸 바로잡은 진단 순서까지 담았습니다.

배포가 느릴 때 추측 말고 단계별로 재야 하는 이유
사내 그룹웨어 배포가 대략 9분(추정) 걸려 서버의 앱 빌드 222초를 8초로 줄였지만 배포는 여전히 5분을 넘겼습니다. 단계마다 시간을 찍어 진짜 병목을 찾고 540초를 332초로 줄인 과정과 일부러 남긴 단계의 기준을 담았습니다.