서버 장애

문제

며칠 전 저녁에 위키를 구동하는 웹서버 하나가 응답하지 않는다는 사실을 알게 됐습니다. 모니터링 소프트웨어가 슬랙을 통해 메모리 부족 경고 외에도 디스크 응답속도 저하, CPU 점유율 상승 경고를 보내왔습니다. 이미 이전부터 슬랙을 통해 너무 많은 경고를 받고 있어 신경쓰지 않고 있었습니다. 오히려 서버가 돌며 이 정도 메시지는 원래 표시되는 건가 생각하고 있어 왔습니다. 메모리 점유율 문제는 처음 인스턴스를 만들고 나서는 일어나지 않았지만 지난 몇 달 동안 문제가 일어나고 있었습니다. 여러 가지 시도를 하다가 그냥 스왑 크기를 아주 크게 설정해서 서비스가 중단되지는 않는 수준을 유지하고 있었습니다. 더 이상 어떻게 튜닝해야 할지도 몰랐습니다. 다만 지금보다 비용을 늘려 큰 인스턴스를 사용할 생각은 별로 없었습니다. 이런 상황에서 장애가 일어났습니다. 클라우드플레어는 이미 웹서버 다운 페이지를 표시하고 있었고 서버 콘솔에 접근할 수 없었으며 라이트세일 콘솔에서 재시작 버튼이 동작하지 않았습니다. 이 상황에서도 라이트세일 모니터링은 서버 상태를 확인할 수 있다고 주장했고 CPU 사용률이 정상이라고 보고했습니다.

평소 이런 상황일 때 라이트세일 웹 콘솔의 '재시작'은 잘 동작하지 않는다는 것을 알고 있었습니다. '중지'를 누르고 기다린 다음 '시작'을 누르면 서버가 재시작되고 정상으로 돌아왔습니다. 이번에도 그럴 거라고 생각했습니다. 하지만 여러 번 중지와 시작을 반복해도 서비스는 복구되지 않았습니다. 처음 '시작'을 누른 시점부터 원격으로 콘솔에 접근할 수는 있었습니다. 콘솔에 접근해서 상황을 알아볼 작정이었습니다. 일단 디렉토리를 옮기려고 앞 글자를 타이핑한 다음 탭키를 누르자 이전에 본 적 없는 메시지가 나타났고 제가 기대한 나머지 경로가 자동으로 입력되는 동작은 일어나지 않았습니다.

Error: read only file system

상황을 이해하는데 시간이 좀 걸렸습니다. 윈도우를 사용하며 파일시스템 장애를 겪은 적이 있었지만 이런 양상은 아니었습니다. 그래서 이게 파일시스템 장애상황이라는 것을 이해하는데 시간이 필요했습니다. 처음에는 메시지를 보고서도 무슨 상황인지 이해하지 못했습니다. 구글에 에러메시지를 검색해보고 나서야 이게 뭔가 잘못됐고 파일시스템에 장애가 생겼으며 파일시스템 전체가 읽기전용인 상황이고 이로 인해 파일을 써야만 하는 모든 동작 - 가령 로그를 써야 하는 웹서버, 이전에 입력했던 커맨드를 보여주는 쉘 등 - 이 제대로 동작하지 않는 상황을 이해하게 됐습니다.

파일시스템에 문제가 있더라도 일단 인스턴스가 시작됐고 몇몇 커맨드를 사용할 수는 있어 보였습니다. 방법이 있을 거라고 생각했고 정 안되면 새벽시간대에 자동으로 만들어진 스냅샷으로 새 인스턴스를 만들면 해결될 거라고 생각했기 때문에 마음은 편했습니다. 다만 이런 작업을 하며 작업 상황을 기록하는데 사용하던 위키를 사용할 수 없어 엄청나게 답답했습니다.

조사

제 상황과 가장 가까운 것으로 보이는 이 페이지를 따라 시도해보기로 했습니다. 이 글은 EC2 사례지만 라이트세일에도 거의 비슷하게 적용할 수 있을 것 같아 보였습니다. 먼저 상황을 파악해봤습니다.

$ touch file Error: read only file system

같은 상황이었습니다. 이날 낮까지 웹서버는 정상 동작했습니다. 지금에 와서야 지난 몇 달 동안의 동작이 정상이 아니라는 사실을 알게 됐지만 어쨌든 웹서비스가 동작하는 상태였습니다. 하지만 모니터링 기록을 보니 서버가 이 상태가 되기 몇 시간 전부터 CPU 점유율이 널뛰고 있었고 스토리지 응답속도가 느려지고 있었습니다. 하지만 이전부터 웹서비스의 응답속도는 느린 편이었기 때문에 응답속도 측정 기록으로는 뚜렷한 변화를 파악할 수 없었습니다. 하지만 전반적으로 이전에 비해 상태가 급격히 나빠지고 있었습니다.

상황은 파일시스템에 서비스를 유지한 상태로는 복구할 수 없는 문제가 생겼고 문제를 악화시키지 않는 방법으로 운영체제가 파일시스템을 읽기전용으로 만들어 현 상태를 유지하려는 동작인 것 같았습니다. 해결방법은 윈도우에서 파일시스템에 문제가 생길 때와 비슷했습니다. 파일시스템을 검사해 문제를 해결한 다음 시스템을 재시작하고 문제가 해결됐는지 확인하는 겁니다. 만약 문제가 해결된다면 다행이고 그렇지 않으면 다음으로 넘어가야 할 겁니다. 위 글은 EC2 기준으로 작성되어서인지 글에 언급된 이름과 같은 스토리지 디바이스는 없었습니다. 하지만 이 전에 이 인스턴스에 연결된 스토리지 디바이스 이름이 xvda1이라는 것을 알고 있었습니다.

$ mount -l | grep xvda1 /dev/xvda1 on / type ext4 (ro,relatime,data=ordered) [cloudimg-rootfs]

이 메시지의 핵심은 스토리지 디바이스의 상태가 ro라는 점입니다. 이 화면을 이전까지는 한번도 볼 일이 없었지만 이 디바이스가 제대로 동작하고 있다면 rw라고 나타나야 하는 모양입니다.

시도

윈도우에서는 chkdsk를 사용했는데 리눅스에서는 fsck라는 유틸리티를 사용헸습니다.

문제가 해결되지 않았습니다. 다시 검색해보니 스토리지 디바이스를 리마운트 해보라고도 되어 있었습니다. 현재 사용중인 하나뿐인 스토리지 디바이스를 어떻게 리마운트 할 수 있는지 잘 이해되진 않았지만 여튼 해봤습니다.

rw라고 표시됐습니다. 원하는 정확한 상태처럼 보였습니다. 이제 재시작하면 모든 것이 정상화될 것을 기대했습니다. 하지만 여전히 reboot 커맨드는 동작하지 않았습니다. 라이트세일 웹 콘솔에서 인스턴스를 중지시켰다가 다시 실행하고 기다렸습니다. 재시작에는 몇 분이 걸렸습니다.

실패

재시작된 인스턴스의 스토리지 디바이스는 여전히 읽기전용 상태였고 위 과정을 몇 번 더 반복해봤지만 이제 fsck 커맨드를 실행한 다음에도 스토리지 디바이스가 rw상태로 변하지 않았습니다. 이 작업을 시작할 때 수동으로 생성한 스냅샷으로 인스턴스를 재생성해서 같은 작업을 해봤지만 여전히 소용 없었습니다. 그래서 마지막으로 자동 생성된 스냅샷으로부터 약 20시간 정도 변경사항을 유실할 각오를 하고 자동 생성된 최신 스냅샷으로부터 인스턴스를 생성했습니다. 그런데 새로 생성한 인스턴스도 같은 상태였습니다. 웹서버는 실행되지 않았고 스토리지 디바이스는 읽기전용인 상태였습니다. 이제 슬슬 걱정되기 시작했습니다. 나머지 스냅샷 모두 이런 상태일 수도 있었습니다. 만약 그렇다면 상황은 훨씬 귀찮아질 겁니다. 인스턴스가 실행은 되니 일단 파일을 모두 꺼내고 새 인스턴스를 만들어 필요한 소프트웨어를 설치하고 설정한 다음 방금 꺼낸 파일을 복구하는 모든 절차를 생각하니 벌써부터 우울해졌습니다. 이런 걸 하려고 VPS를 사용하기 시작한 것은 아니었는데 말입니다.

어차피 거의 망한 거 조금만 더 테스트해보자 싶어 ap-northeast-2b에 스냅샷으로 인스턴스를 생성해봤습니다. 지금까지는 ap-northeast-2a에서 인스턴스를 운용하고 있었습니다. 그런데 2b에는 아예 스냅샷을 통한 인스턴스 생성이 안됐습니다. 다시 한 번 ap-northeast-2c에 스냅샷으로 인스턴스를 생성했고 이 가용영역에는 인스턴스가 생성됐습니다. 하지만 인스턴스를 생성하고 접근해보니 여전히 스토리지 디바이스는 읽기전용 상태였습니다. 마지막으로 한번 더 fsck를 실행했습니다.

이번에는 재시작도 잘 됐습니다. 웹서버가 실행되기 시작했습니다. 클라우드플레어 보안설정 때문에 자잘한 설정을 바꾸지 않고서는 서비스가 정상 동작하는지 브라우저를 통해 확인할 수가 없었습니다. 그래서 일단 동작하는 것 같으니 바로 클라우드플레어 대시보드에서 아이피를 변경해 새 인스턴스를 연결해봤습니다. 이 시점에서 이전까지 쓰던 고정아이피를 이미 삭제해버렸기 때문에 새 고정아이피를 받아 DNS 설정을 변경해야 했습니다. 사이트는 원래대로 돌아왔습니다. 아무일도 일어나지 않은 것 같았습니다. 모니터링 사이트에도 원래대로 표시되기 시작했습니다.

효과

모니터링 사이트가 이 서버의 디스크립션이 바뀌었고 방금 재시작됐으며 스왑 공간이 50% 미만이라고 동시에 보고했습니다. 이전에 웹서버가 메모리를 반환하지 않고 계속해서 가용 메모리가 줄어들어 스왑파일을 깊숙하게 사용한 다음에야 메모리를 찔끔찔끔 반환하는 문제가 있었습니다. 이 상황을 해결해보려고 이것저것 찾아보고 남들이 하는 튜닝을 시도했으나 예상보다 적은 효과에 스왑 크기를 크게 잡아 대응하고 있었습니다. 스냅샷으로 인스턴스를 생성해보니 스왑파일이 없어져 있었고 그래서 문제를 보고한 것이었습니다. 이제 생각해보니 원래 이 크기의 인스턴스는 스왑이 0이었습니다. 그래서 일단 스왑을 이전과 똑같이 크게 설정해 모니터링 사이트의 보고를 해결했습니다.

이상한 일이 일어났습니다. 한동안 모니터링해보니 웹서버 설정은 딱히 바뀐 것이 없었는데 웹서버가 이전과 달리 메모리를 제때 반환해 가용 메모리가 충분한 상태로 유지됐습니다. 한동안 더 살펴보다가 웹서버가 더 늦게 메모리를 반환하도록 설정을 조금씩 바꿔봤습니다. 이전에는 이렇게 설정하면 사용 메모리를 모두 소진하고 스왑파일 깊숙한 곳까지 사용해 응답속도가 떨어지곤 했는데 이번에는 같은 설정에 스왑 근처에도 가지 않았습니다. 아무리 생각해도 이건 인스턴스를 새로 생성한 효과처럼 보였습니다.

추측

모니터링 소프트웨어를 사용하기 시작한지 이제 몇 달 쯤 지났는데 이전 인스턴스를 사용할 때와 새 인스턴스를 사용할 때 값이 어떻게 다른지 긴 시간에 걸쳐 비교해보기 시작했습니다. 뭔가 이상한 점이 있었습니다.

지난 몇 달에 걸쳐 웹서버의 응답속도가 서서히 감소하고 동시에 응답시간이 계속해서 서서히 증가하고 있었습니다. 그러다가 몇 시간 동안 장애를 겪은 다음 새 인스턴스에서는 이 현상이 모두 사라졌습니다. 심지어 새 인스턴스는 이전 인스턴스를 만들어 처음 모니터링을 시작할 때보다 훨씬 상태가 좋았습니다. 속도와 응답속도 양쪽 모두 빨랐습니다. 잠깐 동안은 인스턴스 플랜을 잘못 선택한 줄 알았습니다. 그것도 아니었습니다.

서비스를 중단시키지 않으려고 크게 설정해둔 스왑 역시 전혀 사용하지 않고 있었습니다. 이 모든 상황으로 미루어 인스턴스 자체에 내가 파악할 수 없는 어떤 문제가 있었고 이 문제로 인해 성능 저하가 일어난 끝에 장애가 발생했으며 같은 가용영역에 인스턴스를 생성해도 같은 장애가 일어났습니다. 하지만 다른 가용영역에 인스턴스를 생성하자 문제를 더이상 겪지 않게 된 것 같습니다.

교훈

모니터링 소프트웨어는 지난 몇 달에 걸쳐 지속적으로 성능이 감소하는 상태를 기록해 왔습니다. 하지만 모니터링 소프트웨어의 보고 체계는 짧은 시간 안에 급격한 변화가 일어날 때 알려주도록 되어 있었습니다. 가령 지난 몇 분 동안 CPU 사용률이 높다든지 가용 메모리가 20% 미만으로 감소한다든지 스토리지 디바이스가 몇 초에 걸쳐 응답이 느려질 때 보고했습니다. 하지만 이렇게 긴 기간에 걸친 성능의 변화는 보고 대상이 아니었습니다. 하지만 이제와서 그래프를 보면 뭔가 서서히 잘못돼 가는 상황을 알 수 있었습니다. 모니터링 소프트웨어를 좀더 둘러보고 이렇게 장기간에 걸친 변화를 별도로 보고할 규칙을 만들 수 있는지 알아봐야겠습니다. 가령 월 단위로 두달 전 평균과 한달 전 평균을 비교해 차이가 있다면 별도로 보고하게 해야 합니다.

웹서버를 클라우드플레어 뒤에 놓고 운용해 왔습니다. 저 같은 초보자가 라이브 서비스하는 웹서버를 잘 관리할 가능성은 없기 때문에 클라우드플레어가 웹서버 앞에서 여러 가지 문제를 미리 해결해 큰 도움을 받고 있습니다. 하지만 장애상황에서는 클라우드플레어의 보안 설정을 충실히 이행한 덕분에 웹 프론트엔드에는 접근조차 할 수 없었습니다. 오리진 서버는 클라우드플레어의 알려진 아이피로부터만 접근을 허용했고 유효한 오리진 인증서를 사용해야만 했고 클라우드플레어로부터의 요청에는 항상 약속한 인증서만을 사용해야 했습니다. 여기에 로그인이 필요한 영역은 지정된 VPN을 통해야 하고 클라우드플레어 액세스를 통해 인증을 받은 다음 1시간마다 변경되는 유효한 토큰을 유지해야 했습니다. 평소에는 이런 설정들에 딱히 문제가 없었지만 장애상황에서는 이 설정 대부분을 변경하지 않고서는 상황파악조차 할 수 없었습니다.

기존에는 모니터링서버와 웹서버가 같은 ap-northeast-2a 가용영역에 있었는데 이번 장애를 겪으면서 웹서버를 ap-northeast-2c 가용영역으로 옮기면서 가용영역 장애에 동시에 고장나지 않게 됐습니다. 잠깐 동안 모니터링서버가 아예 다른 데이터센터에 있으면 어떨지 생각해봤는데 지금은 서버 사이에 프라이빗 아이피로 통신하고 있으므로 여기저기 손을 대야 할 것 같아 일단 그렇게까지는 아지 않기로 했습니다.

거의 가지고 놀 목적으로 운용하는 웹서버에 비용을 더 들이기는 꺼려지지만 이런 장애상황을 줄이기 위해서는 결국 서버를 이중화하고 앞에 로드밸런스를 붙여야 할 것으로 보입니다. 라이트세일에서는 로드밸런스 서비스가 월 18달러 정액제이고 클라우드플레어에서는 월 50만 쿼리까지 5달러입니다. 하지만 이쪽은 생각만 하고 실행하지는 않을 작정입니다. 라이트세일의 로드밸런스 비용은 장애가 일어난 웹서버 비용보다 더 비쌉니다. 언젠가 이런 체계가 꼭 필요한 시점이 오면 실행할지도 모르지만 지금은 아닙니다.

다만 다음에 비슷한 문제가 일어나면 모니터링 소프트웨어로부터 미리 보고를 받을 수 있도록 설정하고 장애가 일어날 때 이번처럼 우왕좌왕하지 않고 그냥 따라할 수 있도록 매뉴얼을 만들어놓는 정도로 마무리할 작정입니다. 또 백업을 스냅샷에만 의존하는 대신 다른 스토리지 디바이스를 붙여서 파일 단위로 꺼낼 수 있게 준비해둘지도 고민중입니다.