오늘은 지난번에 올렸던 "VITO CI/CD 변천사 첫번째" 이야기에 이어지는 두번째 이야기입니다.
Scalability
Scalability는 대규모 서비스에서 1순위로 고려해야 할 문제일 것입니다. 꼭 대규모 서비스가 아니더라도 Scalability는 서비스에서 첫번째로 중요한 문제일 것입니다. DAU 10명에서 100명으로 넘어갈 때도 Scalability가 발목을 잡을 것이고, 1,000명에서 10,000명으로 넘어갈 때도 발목을 잡게 됩니다. 비단 트래픽만의 문제는 아닙니다. 서비스의 기능이 추가되고 성능이 개선되면서 컴포넌트의 교체, 추가가 빈번하게 일어나는 상황도 하나의 Scalability 문제라고 할 수 있습니다.
VITO에서도 역시 Scalability에 대해 큰 고민이 있었습니다. 이는 기존의 EC2 서버 Set와 Ansible을 기반으로 한 시스템에서 ECS로, 그리고 최종적으로 Kubernetes로 이전하게 된 결정적인 이유가 되었습니다.
기존 시스템에서 겪었던 어려움
먼저 기존 시스템에서 VITO팀이 겪었던 어려움을 정리해보도록 하겠습니다. Scalability는 위에서도 언급했듯이 다양하게 해석될 수 있는 주제입니다. 우리가 이야기할 Scalability가 어떤 맥락을 가진 이야기인지에 대해 먼저 설명하려고 합니다.
1) 서버 스케일링
당연하게도, 기존의 VITO 서비스는 Application 레벨에서 Scalable했습니다. 즉, 트래픽이 2배로 Linear하게 늘어났을 때 실행되는 컨테이너 수를 2배로 늘리면 트래픽을 버틸 수 있는 구조였다는 뜻입니다.
물론 인프라도 Scalable 했습니다. EPM (Enqueue per Minute, 이전 포스팅 참고)이 증가하면 하나의 서버 Set를 추가하고, 감소하면 Set를 제거하는 등 자동화가 되어있었기 때문에 이론적으로는 완벽했습니다. 하지만 현실은 그렇게 녹록하지 않았습니다. 우리가 한땀한땀 만든 배포 시스템은 여러가지 문제를 맞이했습니다.
2) Granularity — 스케일링의 세밀함
VITO 서비스의 Sommers System은 각 컴포넌트간의 개수의 조화가 중요합니다. 특정 컴포넌트가 뒤따라오는 컴포넌트에 비해 Throughput이 높으면 뒤따라오는 컴포넌트는 처리량을 따라가지 못하므로 많은 양의 메시지 처리를 지연시키게 됩니다.
Queue가 delay 되더라도 각 컴포넌트에 부하가 골고루 나누어져야 각 유저들이 겪을 수 있는 처리 지연시간이 균등하게 나누어집니다. 이를 위해 VITO 서비스는 이전 포스팅에서 이야기한 Set라는 단위로 그룹 스케일링을 진행하였습니다. 항상 같은 비율로 컴포넌트가 실행되면서 컴포넌트간의 조화를 유지시키도록 하기 위해서요.
하지만 이러한 그룹 스케일링은 여러가지 문제를 일으켰습니다.
첫번째는 '자원의 낭비'였습니다. 항상 같은 비율로 스케일링을 하기 위해 스케일링 단위가 가장 큰 컴포넌트를 기준으로 스케일링을 트리거해야 했습니다. 예를 들어, 컴포넌트 A는 한대당 500 EPM을 처리할 수 있고, B는 한대당 100 EPM을 처리할 수 있다고 가정해 봅니다. 이 2개의 컴포넌트를 묶어서 스케일링을 하려면 다음과 같은 단위로 스케일링이 일어나야 합니다.
0 ~ 500 EPM - 컴포넌트 A: 1대, 컴포넌트 B: 5대
500 ~ 1000 EPM - 컴포넌트 A: 2대, 컴포넌트 B: 10대
1000 ~ 1500 EPM - 컴포넌트 A: 3대, 컴포넌트 B: 15대
위의 예시에서 볼 수 있듯이 컴포넌트 B는 스케일링의 경계선에서 불필요하게 많이 실행되고 있었습니다. 만약 컴포넌트 B가 GPU를 사용하는 비싼 자원이라면 이 문제는 그냥 놔둘 수 없는 문제였습니다.
두번째는 '조화의 붕괴'였습니다. Set를 구성하기 위한 컴포넌트간의 비율은 이상적인 상황에서의 비율이었습니다. 특정한 종류의 input이 많은 상황에서는 중간에 있는 컴포넌트 A가 효율이 떨어져 처리량이 낮아질 가능성이 있습니다. 이 경우에 컴포넌트 A를 더 많이 증설하여 해결할 수 있겠지만, 스케일링은 항상 그룹 단위로 일어나기 때문에 컴포넌트 A만 증설하는 것은 어려운 일이었습니다.
3) Mutability — 스케일링 정책의 수정
이러한 세밀함의 부족함에도 우리 서비스는 미려하게 잘 작동했습니다. 낭비는 조금 있었지만 트래픽의 변화를 잘 버텨냈고, 지연으로 인한 고객들의 불편함도 최소화하였습니다. Sommers의 음성인식 엔진이 업데이트 되기 전까지는요.
보다 나은 음성인식 성능을 자랑하는 Sommers 엔진의 새로운 버전에 대한 연구가 끝나고 서비스에 투입하기 위한 과정에서 우리는 전쟁을 겪었습니다. 기존 컴포넌트들을 위한 Ansible 스크립트들을 새로운 컴포넌트에 맞춰 대폭 수정해야 했으며, 각 Set에서의 조화로운 컴포넌트 비율을 다시 찾아야 했습니다.
하나의 Set를 구성하는 EC2 인스턴스에서 우리는 각 컴포넌트를 몇대씩 실행해야 하는지를 계산하였습니다. 정해진 vCPU 개수에서 총 12대의 컴포넌트를 띄우면 컴포넌트당 vCPU는 몇 퍼센트씩 돌아가는지, 특정 컴포넌트 개수가 부족해서 더 실행하면 다른 컴포넌트들은 얼마만큼의 vCPU와 메모리를 손해보는지 등등 최적값을 찾기 위한 계산식은 어려운 최적화 문제로 변질이 되었습니다.
또한 어느정도 최적의 비율을 찾더라도 확신이 있을때까지는 Auto Scaling을 다시 활성화시키지 못하였습니다. 잘못된 기준으로 한 스케일링은 서비스 장애로 이어지기 때문입니다.
이와 같이 어려움을 겪은 VITO팀은 기존의 낡은 서비스 구성방식을 버리고 Container Orchestration의 세계로 이사하기로 마음을 먹었습니다. 장비 스펙을 기반으로 서버를 실행하는 방식이 아닌 컨테이너를 기반으로 한 사고를 하기로 방향성을 새롭게 잡은 것입니다.
Container Orchestration
컨테이너를 기반으로 한 시스템으로 옮기기 위해 우리는 Amazon ECS를 출발점으로 삼았습니다. 왜 Kubernetes가 아닌 ECS를 선택했는지에 대한 이야기는 나중에 하고, ECS로 이전함에 따라 어떤 개선점이 있었는지에 대해 이야기해 보겠습니다.
1) 컨테이너 배치 전략의 유연화
VITO의 기존 시스템에서도 각 컴포넌트는 컨테이너 기반으로 실행이 되었습니다. 하지만 사용하던 방식은 서버에 JVM을 설치해서 Tomcat위에 WAS 컨테이너를 띄우는 것과 같았습니다. 자원의 분배와 배치 전략을 우리가 투명하게 관리하고 있었습니다.
컨테이너의 배치 전략을 ECS로 위임하면서 우리는 기존보다 더욱 유연한 스케일링 전략을 선택할 수 있었습니다. 스케일링 전략을 'Set'가 아닌 각 '컴포넌트'를 단위로 한 전략으로 변경하면서 더욱 세밀한 스케일링을 할 수 있게 됐고 EC2 Instance에 대한 스케일링 전략과 컨테이너에 대한 스케일링 전략을 분리하게 되면서 더 가볍게 전략을 수정하는 것이 가능했습니다.
2) 정책 수정의 간편화
기존에는 배포 및 스케일링 정책을 수정하기 위해서는 Ansible 스크립트와 그를 실행하는 Jenkins Groovy Script를 수정해야 했습니다. 또한 새로운 사람이 이에 대해 학습하는 비용도 매우 컸습니다. 하지만 ECS에서는 표준적이고 자동화된 스케일링 정책이 마련되어 있습니다. ECS 뿐 아니라 더 많은 기능을 가진 Kubernetes의 환경에서의 경험이 있는 사람이라면 쉽게 정책을 수정할 수 있도록 개선이 되었습니다. 이제 Ansible 스크립트는 단 한줄도 남아있지 않게 되었습니다!
3) 돌발상황에 대한 대응 강화
위에서 이야기한 내용과는 별개로 AWS에서 인프라를 운영하면 각종 돌발상황을 많이 겪게 됩니다. 특정 Zone의 장애상황이 발생하는 이슈, 데이터센터에 GPU 자원이 부족하여 할당에 실패하는 이슈 등 예상치 못한 상황을 많이 겪을 가능성이 있습니다.
기존 Ansible과 Jenkins기반 스크립트에서는 이러한 돌발상황에 대한 예외 처리를 직접 해야 했습니다. GPU 할당에 실패하면 그것을 성공할 때까지 누군가가 계속 할당 시도 버튼을 눌러야 했습니다. 하지만 ECS와 EKS는 실패한 할당에 대한 재시도 로직이 내장되어 있는 등 전세계 사람들이 겪었던 돌발상황에 대한 예외처리가 이미 되어 있었습니다. 또한 Multi-AZ도 별다른 노력을 하지 않아도 구성할 수 있어서 간단하게 도입할 수 있었습니다.
4) 그럼에도 불구하고 Kubernetes로
컨테이너 배치 전략을 ECS로 이전하면서 많은 부분에 있어 성공적인 개선을 이루었습니다. 사실 첫 Container Orchestration 도구로 ECS를 선택한 이유는 '팀에서 이전을 리드하는 담당자가 ECS 운영 경험이 훨씬 길었기 때문'입니다.
익숙하고 성공적인 시스템이었음에도 불구하고 우리는 Kubernetes로의 이전을 결심하게 되었습니다. 이번 포스팅에서 그 이야기를 모두 풀어내기는 어려울 것 같아 다음 포스팅에서 'VITO 팀이 Kubernetes로 이전하게 된 이유'와 '현재 VITO 시스템이 어떻게 이루어져 있는지'에 대해서 이야기해 보도록 하겠습니다.
'AI 이야기' 카테고리의 다른 글
[AI 뉴스] 그림 그려주는 인공지능 DALL-E (2) | 2022.09.05 |
---|---|
[AI뉴스] 2021년, AI 핫피플들의 토론 - AI 업계의 트렌드와 미래는? (2) | 2022.09.01 |
[AI뉴스] 누구나 간편하게 딥페이크 영상 만들기 (0) | 2022.08.30 |
[AI뉴스] 2020년 AI 핫이슈 베스트 5 (0) | 2022.08.25 |
VITO CI/CD 변천사 첫번째 - 손스케일링 (0) | 2022.08.18 |
댓글