Mar 302016
 

 

모든 시스템은 문제가 생기기 마련이다

“사람은 누구나 실수를 하기 마련이다. (To err is human)”라는 말처럼 모든 시스템은 문제가 생기기 마련입니다. 사람이 만들었으니까… 특히 여러개의 단위 시스템들로 구성된 복합 시스템을 클라우드 상에서 운영한다면 통제할 수 없는 다양한 변수들이 당신을 괴롭힐 겁니다. 낮에도, 밤에도, 트래픽이 많을 때에도, 적을 때에도 문제는 항상 생깁니다.

Screen Shot 2016-03-30 at 9.05.59 AM

Nudge는 AWS 상에서 수십 대의 인스턴스로 구성된 어플리케이션 서버, 워커,  5가지 데이터베이스 (mySQL, redis, memcached, Couchbase, Elasticsearch 등) 클러스터 등을 운영하여 글로벌 기업 고객들에게 24/7 무중단 서비스를 제공하고 있습니다. 이 글에서는 시스템에 이상 징후가 발생했을 때 어떻게 효과적으로 대응할 것인가에 대한, 지난 4년간의 저희 나름대로의 해결책을 공유하고자 합니다.

 

먼저 용어부터 정의하고

  • Alert: 얼럿은 “시스템에 이상 징후가 있으니 확인해서 대응하라. “라는 알림으로 시스템 별로 설정합니다. 특정 프로세스에서는 이메일로, 모니터링 시스템에서는 alarm으로, 주기적으로 확인하는 heartbeat에서는 expired 등으로 발생됩니다.
  • On-Call 엔지니어: 특정 기간 (보통 12시간) 동안 시스템 alert를 1차적으로 확인하고 처리할 담당 엔지니어를 말하며 자신이 처리하기 힘든 이슈라면 해당 시스템의 담당 엔지니어에게 연락합니다.
  • On-Call 스케쥴: 누가 언제 On-Call 엔지니어로 근무할지를 정하는 일정을 말합니다.

 

가정

각 어플리케이션, 데이터베이스 등에서 모니터링해야 하는 metrics은 이미 정의가 되어 있고 어떤 모니터링 툴을 이용해서 어떤 경우에 어떤 alert를 발생시킬 것인가는 설정되어 있다고 가정하겠습니다. 해당 메트릭과 모니터링 툴에 대한 논의는 너무 광범위한 주제라서 이 글의 범위를 벗어난다고 생각합니다.  이 글에서는 Alert를 어떻게 분류하고 발생한 Alert를 누가 (On-Call) 어떤 프로세스에 따라 처리하는 것이 효과적인가에 대해서만 다루겠습니다.

 

내일 새벽에는 누가 일어날까?

Alert이 발생한 경우 누가 처리를 할 것인가를 정해야 합니다. 낮에 발생하면 큰 문제가 아니겠지만 밤이 문제죠. 24/7 운영을 한다면 제가 자는 시간에 서비스의 피크시간대가 있을 수 있겠죠. 24/7 시스템을 모니터링하고 운영하는 업무를 전담하는 시스템 엔지니어가 있다면 좋겠지만 대부분의 스타트업에서 그런 시스템 엔지니어를 채용하기란 쉽지 않습니다. 인원도 적어서 대개는 해당 시스템을 개발한 엔지니어가 직접 해당 이슈에 대응할 수 밖에 없습니다. 결국 한 사람에게 스트레스가 편중될 수 밖에 없고 장기간 지속되면 편하게 잠을 자기도 어렵습니다. 새벽에 alert이 발생해서 처리하고 다시 잠자리에 든 날은 하루종일 안좋은 컨디션으로 일을 하게 되고 심하면 하루를 완전히 날릴 수도 있습니다. 해당 시스템에 대응할 수 있는 사람이 여러 명인 경우에도 문제는 발생합니다. 모두의 마블 책임은 누구의 책임도 아니기 때문입니다. 결국에는 순번을 정해서 불침번을 서야 하는데 alert이 발생했을 때 대응할 수 있는 지식을 가지고 있지 못한 사람이 On-Call 담당자라면 ‘인간 자명종’으로 전락할 수 밖에 없습니다. 지식을 가진 사람에게 전화를 걸어 깨울 수 밖에 없습니다. -_- Alert이 발생해서 일어났더니 별일이 아니라고 한다면 그것 또한 팀에 큰 손실이 됩니다.

 

Alert & On-Call 정책

이런 비효율을 제거하기 위해 올바른 정책을 수립하고 그에 맞는 시스템을 도입해야 합니다. 저희는 1명에게 스트레스가 집중되는 문제, 심각한 alert이 발생했음에도 자꾸 놓치고 빠른 대응을 하지 못하는 것, 체계적인 기록과 관리가 안되는 문제 등이 있었습니다.

  • 일은 나눠야 한다. 시스템 전체에 대한 전문 지식을 가지고 있지 않아도 1차 대응을 할 수 있어야 한다.
  • 시스템 이슈의 심각도가 높을수록 빠른 대응이 필요하다.
  • On-Call 스케쥴을 통해 마음의 준비를 할 수 있어야 한다.
  • 공평해야 한다.
  • 나머지는 포기한다.

여기서 제일 중요한 정책은 맨 마지막 정책입니다. 모든 걸 다 하려고 하다가 아무것도 하지 못하고 계속 고민만 하는 상황을 끊어야 합니다.

그럼 위의 정책에 따라 alert를 분류하고 critical alert이 발생했을 때 어떻게 대응하고 처리할 것인가에 대해 살펴 보겠습니다.

 

자다가 일어나야 하는가?

Alert를 분류하는 방법은 생각보다 간단합니다. 제일 심각한 것부터 덜 심각한 순으로 분류하면 됩니다. 중요한 것을 처리하는 것이 가장 임팩트가 높기 때문에 심각한 것부터 정의해서 절차를 만들면 됩니다. 저희는 현재 3단계까지 분류해서 사용 중입니다.

여기서 가장 중요한 질문은 “자다가 일어나야 하는가?”입니다. (저희가 찾은 최고의 질문이었습니다.) 특정 상황이 발생했을 때 누군가가 일어나서 처리할 만한 문제이냐를 생각해 보면 됩니다. 이 경우는 심각한 상황이 이미 발생했거나 또는 일이 더 커지기 전에 누군가 일어나서 대응해야만 하는 상황 등을 의미합니다. 이런 상황에는 alert notification 시스템을 이용해서 당장 On-Call 엔지니어를 깨워서 대응하도록 해야 합니다. 아래는 critical alert의 예시입니다.

Critical (자다가 일어나야 한다.)
  • Fail-over가 일어난 경우
  • Database에 접속이 안되는 경우
  • Database 컨넥션이 일정 값 이하로 떨어진 경우
  • 특정 클러스터의 노드 중 AWS 특정 region (us-east-1a)에 위치한 노드가 3대 이상 문제가 발생해서 시스템 안정성에 문제가 발생한 경우

여기서 “아침에 일어나서 처리해도 되는가?”라는 질문에 ‘네’ 또는 ‘어느 정도는’이라고 답할 수 있는 이슈라면 Critical이 아닌 겁니다.  최대 8시간 정도 경과되더라도 시스템 운영에 큰 영향을 미치지 않는다라고 생각한다면 Severe로 변경했습니다. 엔지니어링팀의 근무 환경과 효율이 가장 중요하기 때문에 특정 시스템의 클러스터에 자꾸 문제가 발생하거나 바로 해결이 어려운 경우는 클러스터의 노드 수를 늘림으로써 critical alert을 severe alert으로 변경시켜 버리는 것도 하나의 방법입니다. 쉽게 말해 당분간 돈으로 해결하는거죠. 😉

Severe (아침에 일어나서 처리하면 된다. 하지만 꼭 처리해야 한다.)
  • Cluster의 일부 node가 죽었지만 QoS에 큰 영향은 없는 경우
  • CPU 사용률이 threshold를 넘은 경우
  • 특정 job이 죽어서 queue에 들어갔는데 복구에 실패했다.

그리고 그외 나머지는 ‘기타’ 버킷에 넣었습니다. 이 바구니에 담긴 이슈들은 On-Call 담당자가 아닌, 해당 시스템의 엔지니어가 확인하고 처리합니다.

기타 (아몰랑)
  • 특정 job이 죽었는데 queue에 들어가서 다시 처리했다.
  • 나.머.지.

저희도 처음에는 이런 분류를 하지 못해서 많이 애를 먹었지만 정리하고 보니 아주 간단한 질문에 대답하기만 하면 된다는 걸 깨달았습니다.

 

계란을 한바구니에 담지 말라

Alert를 잘 분류했더라도 모든 alert, warning들을 하나의 이메일 (예. engineering@abc.com)로 보내면 당연히 낮은 수준의 이메일들이 월등히 많기 때문에 이메일을 확인하는 데 있어 피로도가 증가하고 결국에는 둔감해지면서 무시하게 됩니다. 제목에 [Critical]로 표시하고 레이블로 빨간색을 달아봐야 소용 없습니다. 이메일 더미 속에 critical alert이 포함되어 있고 빨리 발견하고 대응하지 못한다면 시스템 장애는 심각한 수준으로 커질 수 있습니다. 어떤 경우에는 엔지니어링팀의 어느 누구도  이메일 확인을 하지 않아 장애 발생을 모르고 지나가는 일도 벌어질 수 있습니다.

따라서 alert 종류에 따라 다른 바구니 (notification 방법)를 사용하는 것이 좋습니다. 예를 들어 critical은 별도의 alert 알림 시스템을 사용하고, severe는 severe-alerts@abc.com로, 나머지는 warning-alerts@abc.com으로 보냅니다. 그런 다음 On-Call 엔지니어가 critical과 severe를 책임지고 처리하도록 하면 책임과 역할이 명확해 집니다. AWS CloudWatch의 경우 알람에 따라 어떤 것은 critical로 분류되어 있고 어떤 것은 severe로 분류되어 있습니다. 즉 특정 모니터링 툴에서 발생하는 alert들이 모두 동일한 수준이 될 필요는 없습니다.

이렇게 다른 바구니를 사용하면 alert 알림 시스템을 통해 전달된 alert는 자다가도 일어나서 처리해야 할 일이고 severe-alerts@abc.com으로 들어온 이메일은 업무 시간 중에 1순위로 처리해야 할 일 등으로 자연스럽게 인식되기 때문에 바구니 종류만으로도 업무 순서가 쉽게 파악이 됩니다.

 

내 너를 깨우리라.

Nudge는 critical alerts를 관리하기 위해 OpsGenie라는 alert 알림 시스템을 사용하고 있습니다. 예를 들어 critical alert이 발생하면 OpsGenie 시스템이 On-Call 엔지니어에게 스마트폰 푸시 알림, 이메일을 동시에 보내고 3분 안에 해당 엔지니어가 반응 (acknowledge)이 없으면 SMS를 보내고 1분 후에는 전화를 겁니다. 그래도 반응이 없으면 1분 후에 다음 스케쥴에 있는 On-Call에게 SMS를 보내고 전화를 겁니다. 즉 On-Call 엔지니어가 잠에서 깨지 않으면 5분 후에 다른 엔지니어를 깨우는 겁니다.On-Call 엔지니어는 민폐를 끼치지 않으려면 반드시 일어나야 합니다. -_- Policy 설정을 통해 알림의 순서와 시간 간격 등을 원하는대로 설정할 수 있습니다.

저희는 모든 critical alerts를 OpsGenie로 보내고 OpsGenie에 설정된 규칙에 따라 On-Call 엔지니어에게 알림을 보내도록 설정했습니다.  OpsGenie에서 제공하는 integration을 이용해서 AWS CloudWatch (CloudWatch에 설정된 critical alerts), email (어플리케이션 서버 또는 워커가 프로세싱 중 심각한 문제가 생긴 경우 발송하는 이메일), heartbeat (모든 시스템을 모니터링하는 observer 인스턴스에서 1분마다 각 시스템으로 보내는 테스트 스크립트 – i.e. ping, health check, db read/write test, etc – 의 결과) 등을 OpsGenie로 보내고 있습니다.

유사한 서비스로는 VictorOpsPagerDuty 등이 있으며 저희는 OpsGenie가 상대적으로 가격이 저렴하고 heartbeat+라는 기능을 제공해서 선택했습니다.

 

On-Call 스케쥴

On-Call 스케쥴은 팀의 구성인원에 따라 상황에 맞게 짜면 됩니다. 절대적 균등 배분보다는 서로의 상황을 이해하고 배려하는 것이 중요합니다. 누군가가 휴가를 갈 수도 있고 주말에는 시간이 안될 수도 있어서 가끔씩 일정을 조정한곤 합니다. 저희는 현재  3명의 엔지니어가 12시간마다 로테이션하고 있습니다.

 

Zombie-Proof

새벽 3시에 alert이 울려서 일어났는데 머리는 찌끈거리고 아무런 생각도 떠오르지 않는, 그런 날이 있습니다. 정말 좀비가 되면 이런 느낌이 아닐까 싶은 생각이 드는데 긴급 상황이니 일은 처리해야겠고 미칠 것 같습니다. 그러다 보면 실수를 하거나 잘못된 판단을 할 확률이 높아집니다. 특히 자기가 만든 시스템이 아닌 경우에는 위험성이 더 커집니다. 이런 상황을 개인의 책임으로 돌리거나 개개인의 능력으로 알아서 극복하도록 하는 것보다는 시스템적으로 해결하는 것이 낫습니다. 즉 해당 시스템에 대해 잘 모르더라도 기본적인 응급 처치를 할 수 있는 방법이 잘 정리되어 있다면 좀비도 따라 할 수 있겠죠?

따라서 Alert 발생시 대응 매뉴얼을 만들어야 합니다. 간략하게는 DevOps 대쉬보드 같은 문서 (또는 웹페이지)를 만들어서 필요한 정보를 한 곳에서 쉽게 확인할 수 있게 합니다. 접속해야 할 시스템의 IP, 로그를 보기 위해 입력해야 하는 명령어 등 반복적으로 사용하고 잘 변경되지 않는 정보라면 문서에 기록해 두는 것이 좋습니다. ‘잠깐만 찾아보면 되잖아’와 같은 의견은 깔끔하게 무시하고 무조건 기록해 둡시다. 긴급 상황에서 마음이 급해지면 평소에 쉽게 하던 일도 하기 어렵습니다. 추가적으로 각 시스템별 장애 유형과 해결책 등을 정리한 문서를 링크 걸어 두면 해당 내용을 따라하기만 해도 응급 처치를 할 수 있습니다. 약간의 노력과 준비가 있으면 엔지니어링팀의 누구나 On-Call 담당자가 될 수 있습니다.

Screen Shot 2016-03-28 at 5.28.33 PM

<구글독을 이용한 DevOps Dashboard 샘플>

 

On-Call 로그를 남겨라

Alert이 발생하면 반드시 On-Call 로그를 남겨서 기록해야 합니다. On-Call 로그 문서를 열고 양식에 따라 빈칸을 채우기만 하면 됩니다. 양식 아래에는 관련 로그 및 이미지 등을 첨부합니다. 다음 DevOps 미팅 (alert 발생한 날 또는 그 다음 날)에서 해당 케이스를 리뷰하고 개선하는 작업을 진행합니다. 저희는 월 단위로 구글독 문서를 생성하여 작성하고 있습니다.

Screen Shot 2016-03-28 at 4.26.52 PM

<구글독을 이용한 On-Call 로그 샘플>

 

이제 편안하게 자고 있어요

Alert 관리 정책을 수립하고 On-Call 시스템을 구축함으로서 여러가지 긍정적인 효과를 체감하고 있습니다.

  • 긴박한 alert를 놓치는 일이 없어져서 시스템 이슈에 대한 빠른 대응이 가능해졌다.
  • 마음 편하게 잘 수 있다. 문제가 생기면 깨워 줄 테니
  • 시스템 장애에 대한 스트레스 레벨이 낮아졌다. 매뉴얼에 따라 처리하면 된다는 믿음
  • 매뉴얼이 보다 자세해졌다.
  • 시간이 지나면서 모니터링이 더 타이트해 졌고 그 결과로 시스템 안정성이 개선되었다.
  • 엔지니어링팀 모두의 시스템 전반에 대한 이해도가 증가했다.
  • 한명의 엔지니어에게 일이 집중되는 현상이 사라졌다.

 

소회

시스템 장애는 일어나기 마련이니 alert이 발생하면 신속하게 대응해서 처리할 수 있다는 믿음을 가지는게 가장 중요한 일이라고 생각됩니다. 우리는 준비가 잘 되어 있다는 믿음, 내가 하지 못하면 내 동료가 도와줄 것이라는 신뢰 등을 바탕으로 마음의 평화를 찾아야 합니다. 스타트업은 단기전이 아니니까요.

막상 정리해서 쓰고 보니 간단해 보이는데 저희는 몇년이 걸려서 시행착오 끝에 배운 내용입니다. 짧게 쓰려다 보니 줄인 내용이 많아서 언제 한번 오프라인 세션을 통해서 공유를 해도 좋겠네요. 그리고 여러분께서 사용하고 있는 좋은 방법이 있다면 공유 부탁 드려요. 🙂

그리고 가장 중요한 것! 클라우드 상에서 24/7 무중단 비정형 데이터 시스템을 구현하고 운영하는 일에 관심이 있는 엔지니어라면 저희가 동료를 찾고 있으니 지금 바로 지원해 주세요. 고맙습니다.