Defense of the Clones (클론의 방어)
숙연한 공기가 감도는 월요일 이었다. 지난 주말 발생한 대규모 서비스 장애 때문에 누구 하나 쉽게 말을 꺼내기 힘든 분위기였고 차분하고 조용하게 하루가 지나고 있었다. 많은 인기를 얻고 있었던 아이돌 그룹의 싱글 앨범을 단독 공개하는 행사가 있었는데, 앨범 공개 시작 전부터 계정 로그인 서비스부터 뮤직 스토어 서비스, 결제 서비스까지 순식간에 많은 요청이 몰려서 시스템이 대응하기 힘든 상태가 되었다. 결국 계정 정보를 관리하는 서비스가 응답을 제대로 주지 못하는 상황이 되자, 연결되어 있던 수 많은 서비스들도 연달아 기능이 멈추는 대규모 장애로 이어졌다. 전 세계에 있는 아이돌 팬들이 독점 공개 음원을 빠르게 구매하기 위해 발매 시간에 맞춰 다양한 기기로 접속 시도를 했기 때문이었다. 단기간 집중된 접속 요청은 시스템에 과부하를 주었고, 과부하로 인하여 응답이 늦어지기 시작하자, 접속 실패에 따른 재시도가 기하급수적으로 불어났다. 바쁜 사람에게 계속해서 바쁜지 확인하면 일 처리 시간이 더 늘어난다는 것을 이해했다면, 어떤 상황이 벌어졌을 지 상상해 볼 수 있을 것이다. 시스템 과부하가 예상되어 발매일을 연기하면서까지 시스템과 서비스를 점검하고 장비를 증설했음에도 불구하고, 결국 서버 자원을 모두 소진하여 트래픽을 감당하지 못했고 대규모 서비스 불가 상태가 되었던 것이다. 1
그렇게 모든 것이 가라앉은 분위기였지만, 우리 서비스의 운영 PL(Project Leader)의 표정은 괜찮아 보였다. 오히려 초상집에서 분위기 망치지 않으려고 애써 노력하는 것에 더 가까워 보였다. 그리고 운영 주간 회의에서, 표정이 침울하지 않았던 이유를 알게 되었다. 서버를 증설하며 만반의 준비를 했음에도, 우리가 담당했던 허브(Hub) 서비스를 제외하고 모든 서비스가 고객의 요청쇄도에의해 시스템이 마비되었던 것이다. 허브서비스가 유일하게 버틸 수 있었던 것은 머신 이미지(Machine Image) 기반 오토스케일링을 적용해 두었기 때문이었다. 스타워즈의 은하 공화국이 클론 군대를 만들었던 것처럼 허브 서비스는 쿨론 서버를 빠르게 생성해서 급증하는 대규모 트래픽을 감당했다. 2
앞에서 말한 일시적 대규모 사용자 요청으로 인한 시스템 마비 사건이 있기 몇 달전 어느 날이었다. 운영 외주 TA(Technical Architect)와 이야기를 하다가 AWS 콘솔에서 EC2-Auto라고 이름 붙은 인스턴스를 보게 되었다. 사전에 지시한 내용이 아니어서 어떤 용도로 만들었는 지 물어봤다. 그랬더니 오토스케일링 그룹은 AMI(Amazon Machine Image) 기반으로 되기 때문에 배포하는 날 AMI를 생성하기 위해 사용하는 깨끗한 상태의 서버라고 답변을 했다. 서버 설정의 일원화, 자동화, 효율과 및 일관성 관리를 위해 셰프(Chef) 도입을 지시했었고 서버 배포하는 날에는 셰프 명령어만 수행해서 정해진 버전을 서버에 배포하도록 했는데, 그 방법을 쓸 경우 오토스케일링을 해서 서버를 추가할 때 마다 새롭게 추가되는 서버에서 셰프 명령을 적용해 주어야 했다.
이 방법은 1/ 스케일링이 일어나는 중 네트워크 문제로 인해 애플리케이션 패키지 파일을 가져올 수 없게될 경우 배포나 서버 증설이 문제가 생길 수 있고, 2/ 셰프 수행 자동화를 추가로 구현해야 하는 단점이 있었다. 이러한 단점을 극복하기 위해 (월간) 서버 배포 전날 EC2-Auto라는 새로운 인스턴스를 생성하고, 여기서 셰프를 수행한다음 그대로 AMI를 생성한다는 것이었다. 그리고 생성된 AMI를 이용해서 오토스케일링 그룹의 서버를 교체하는 방식으로 배포를 하도록 했다는 것이다. AMI는 이미 만들어져 있기 때문에 언제든지 서버를 클론해서 쉽게 늘리고 줄일 수 있는 장점도 추가도 얻게 되었다. 이러한 방식은 2012년이라는 시기로 봤을 때 한국에서는 보기 드물던 매우 혁신적인 시도였으며, 이후 서비스 운영 방식을 이미지 기반으로 바꾸는 첫 발자국이 되었다. 3 4

머신 이미지는 바이너리로 되어 있기 때문에 다음과 같은 단점이 있다. 1/ 담겨진 내용을 직관적으로 파악하기 어렵다는 단점이 있다. 만약 이미지의 내용을 확인하고 싶다면, 이미지로 새로운 서버를 생성하고 내부에 접속해서 내용을 확인해야 한다. 2/ 또한 같은 이유로 아주 작고 간단한 설정이라도 바로 변경하는 것이 힘들다. 특히 운영 중인 서버에 문제가 생겼을 때 즉시 필요한 만큼 이미지의 내용을 변경하는 것은 불가능하다. 설정 변경이 필요한 경우, 이미지로 새로운 서버를 만들고, 내부에 접속해서 설정을 변경한 다음 새로운 머신 이미지를 별도로 생성해야 한다. 또는 처음부터 변경된 설정으로 이미지를 만들어야 한다.
하지만, 애플리케이션을 포함한 모든 설정을 담은 이미지를 생성해서 서비스 운영을 하는 것은 다음과 같은 장점이 있다. 1/ 서버 시작 시 준비 과정에 소요되는 시간이 적다. 이미 빌드가 끝난 소프트웨어 이므로 바로 동작하기 때문이다. 2/ 같은 이유로, 서버 실행 시 필요한 의존성은 이미 내재되어 있기 때문에 의존성으로 인한 변수가 적다. 빠른 실행 시간과 의존성해결은 일관적이고 예측가능한 서비스 운영환경을 만들어 주는 중요한 장점이다.
그렇다면, 이미지의 단점을 보완하면서 장점을 활용할 수 있는 방법을 찾는 것이 중요할 것이다. 먼저, 이미지 편집에 대해서는 이미지를 구성할 범위를 정하는 것으로 해결할 수 있다. 운영체제와 기본적인 필수 구성요소, 보안 규정만 준수한 이미지를 활용하는 방법이 있다. 이 경우, 서버는 기본 설정만 되어 있으므로 Chef, Ansible 같은 설정 관리(Configuration Management) 도구 또는 단순 스크립트를 통해 동적으로 설정을 적용할 수 있다. 이렇게 하면 긴급하게 운영 서버에 조치를 취해야 할 때 바로 반영 가능하며, 이미지를 새로 생성할 동안 기다리지 않아도 된다.
하지만, 이러한 동적 설정 변경은 뜻하지 않은 치명적인 단점이 있다. 서버가 실행되면서 설정 정보를 가져와야 하기 때문에 부팅 시간이 길어진다. 또한 동시다발적으로 서버가 새로 생성되는 경우 최신 설정을 가져오기 위해 갑작스럽게 네트워크 자원을 많이 사용해서 일부 서버는 설정을 가져오는 작업을 실패하게 된다. 엎친데 덮친격으로 설정 정보를 관리하는 저장소가 과부화가 걸리거나 불능이 될 경우 서비스 전면 장애가 발생한다. 그래서, 그림의 왼쪽에 있는 것과 같이 대부분의 모든 기능을 담은 이미지를 생성하고 활용하는 것이 운영 우수성 측면에 더 적합하다. 하지만, 여전히 이미지 가시성과 이미지 생성 시간이라는 문제가 남는다. 5
이미지의 가시성(Visibility) 문제는 소스코드 기반 이미지 관리 자동화와 런북(Runbook) 기반의 운영 고도화를 통해서 해결할 수 있다. 이미지 자체는 투명하지 않지만, 설계도인 소스 코드를 통해 동작을 확인할 수 있으며, 모든 이미지는 소스 코드로 부터 (파이프라인을 통해) 자동으로 생성되도록 만들고 버전을 기록하도록 하는 것이다. 제품 포장의 이름을 보면 내용물을 추정할 수 있는 것과 같은 원리로 생각하면 된다. 이렇게 이미지를 패키지로 규격화 했다면, 운영에서 문제가 발생했을 때 즉시 이전 버전으로 교체하여 문제를 해결할 수 있게 된다. 우리는 이것을 롤백(Rollback)이라고 부른다. 6 7
이런 전략을 사용한다면, 장애가 발생했을 때 긴급 패치를 위해 이미지를 새로 생성할 필요가 없어진다. 자연스럽게 이미지 생성 시간에 대한 문제도 해결된다. 물론, 모든 장애를 예측할 수 있는 것은 아니기 때문에, 미리 만들어둔 이미지로 되돌릴 수 없다는 주장을 할 수도 있다. 하지만, 그런 주장을 한다면 지속적 전달(Continuous Delivery) 또는 CI/CD Pipeline 8을 제대로 이해하지 못한 것이라고 말하고 싶다. CI/CD Pipeline의 핵심 메시지는 모든 변경은 운영 준비 상태(Production-ready)가 되어야 한다는 것으로, 1/ 소규모 변경을 통해 통제 가능하도록 하고, 2/ 자동화된 절차와 동일한 환경을 통해 테스트를 하고, 3/ 실수를 방지하도록 만들겠다는 것이다. 만약 정말로 모두가 놓친 서비스 장애이고 롤백으로 해결이 불가능한 경우라 하더라도 이미지만 다시 생성하는 시간은 5분도 걸리지 않는다. 9 10
따라서, 이미지 기반으로 서버를 구성해 놓았다면 자동 확장 기술을 활용해서 일시적으로 급격하게 폭증하는 대규모 요청을 처리하는데 효율적으로 대응할 수 있다.
- Circuit Breaker [본문으로]
- 클론의 습격(Attack of the Clones)은 스타워즈의 프리퀄 삼부작 중 두 번째 에피소드다. [본문으로]
- Bakery System [본문으로]
- PhoenixServer [본문으로]
- 실제로 클라우드 스토리지 서비스, 인공지능 서비스, 채팅 플랫폼 운영 담당자들에게 이런 단점을 조언해 주었지만, 자신들의 의견이 옳다고 주장했고 결국 동적 설정 방식을 채택했다. 하지만, 언급한 동일한 원인으로 장애를 겪었다. [본문으로]
- 도커(Docker)에서 해시(Hash)와 버전 태그(Tag)를 기반으로 이미지를 관리하는 것이 일반적으로 널리 쓰이기 전부터, AMI 태그에 Git SHA와 버전을 붙여서 관리했다. [본문으로]
- Immutable Infrastructure [본문으로]
- Continuous Delivery [본문으로]
- CI/CD Pipeline [본문으로]
- 오히려 원인을 분석하는 데 더 많은 시간이 든다. 긴급 상황에서 이미지 생성 시간이 너무 오래 걸리기 때문에 효율적이지 못하다는 것은 변명일 뿐이다. 서버에 접속해서 바로 패치하고 해당 서버로 이미지를 생성한다면 5분정도면 충분하다. [본문으로]