오도근 AWS 솔루션즈 아키텍트

오도근 AWS 솔루션즈 아키텍트
오도근 AWS 솔루션즈 아키텍트

[컴퓨터월드] 1960년대 최초의 단지형 아파트인 마포아파트는 6층이었다. 시간이 지나면서 건축공법, 재료, 도구들이 발전하여 이제는 100층이 넘는 초고층의 빌딩을 지으면서도 에너지와 관리 측면에서 효율성은 마포아파트에 비해 훨씬 좋아졌다.

복잡한 비즈니스를 담고 있는 시스템도 클라이언트/서버, Web기반 3티어, 콤포넌트 기반(CBD), 서비스 기반(SOA)를 거쳐 마이크로서비스 아키텍처(Miscroservice Architecture, 이하 MSA)로 진화했다. 시간이 지나 또 다른 개념이 나타날 수 있겠으나, MSA는 지금까지 가장 진보된 시스템 아키텍처임엔 틀림 없다. 특히, 비즈니스 변화의 속도가 더욱 빨라지고 있는 4차산업혁명 시대에 IT기업들이 가져가야 하는 최고의 전략으로 MSA와 애자일(Agile)이 각광받고 있다.

필자는 여기에서 전통적인 모놀리식 아키텍처(Monolithic Architecture)를 가진 기업들이 당면한 과제를 짚어보고, 그 해결책으로 MSA와 애자일을 제시하려고 한다.


모놀리식 아키텍처의 당면 과제

통상적으로 모놀리식 아키텍처의 단점은 의존성에서 비롯된다. 하나의 모듈을 수정할 때, 이를 참조하거나 영향을 받는 모든 모듈들도 수정을 해야 하기 때문이다. 시스템이 복잡하고 클수록 이러한 영향은 더욱 커지는데, 모듈을 담당하는 팀이 다를 경우엔 일정을 맞추기도 매우 어렵다. 영향도 분석에 더 많은 시간이 소요되고, 테스트와 품질관리도 훨씬 어려워진다. 시스템이 너무 복잡해 영향도 파악이 어려울 경우엔 코드의 중복을 무릅쓰고 동일한 기능을 하는 새 버전을 만들기도 한다.

결과적으로 배포는 월단위가 되고, 주말이나 새벽시간에 진행되기 마련이다. 수정 규모가 큰 경우엔 명절이나 사용자의 트래픽이 적은 연휴에 배포가 이루어지기도 한다. 개발부터 배포까지의 리드 타임이 길어지는 것은 그 만큼 비즈니스 변화의 속도에 시스템이 따라가지 못한다는 의미이다. 하나의 서버에 큰 시스템이 탑재되기 때문에 고사양, 고비용의 서버가 필요하며 경제성 측면에서도 유리하지 못하다.

모놀리식 아키텍처
모놀리식 아키텍처

MSA의 특징

MSA는 독립적이고 작은 서비스들로 구성된 시스템을 의미한다. 모놀리식에서 문제의 원인이었던 서비스들간의 의존성이 약화되거나 제거돼 느슨한 결합(loosely coupled) 상태로 구성된다. 즉, 서비스의 수정이 발생하여도 다른 서비스로의 영향이 없거나 적기 때문에, 독립적인 개발 및 배포가 가능하고 그만큼 테스트와 유지보수도 쉬워진다.

서비스는 저마다 데이터베이스를 가지며, 각 서비스마다 더 적합한 기술이 사용된다. 회사마다 차이는 있지만, 개발부터 테스트까지의 과정이 최대한 자동화되어 하루에도 수 차례 배포되는 경우도 많다. 낮은 사양의 컴퓨팅 리소스를 사용할 수 있어 경제적으로도 효율적이다. 마지막으로 MSA는 클라우드 네이티브라는 접근방식에도 부합하는 아키텍처이다.

마이크로서비스 아키텍처
마이크로서비스 아키텍처

MSA의 특징과 장점

서비스의 크기가 작기 때문에 신규 기능을 그 만큼 빠르게 출시할 수 있고, 고객들이 원하는 것을 더 빠르게, 더 자주 업데이트 할 수 있다. 이는 빠르게 변하는 시장 환경에 민첩하게 대응할 수 있음을 의미 한다. 장애가 발생하더라도 장애 범위가 서비스에만 국한되는데, 이는 곧 고객 입장에서는 앱 전체가 먹통이 되는 것이 아니라 장애 서비스를 제외한 모든 서비스를 정상적으로 사용할 수 있다는 의미가 된다. 특정 이벤트로 대량의 트래픽이 몰릴 경우, 해당 서비스에만 컴퓨팅 리소스를 더 투입하는 스케일 아웃 전략을 적용하기 쉽다.

만약 클라우드 환경에서 서비스를 운영한다면 스케일 인/아웃 전략은 더 큰 효과를 발휘한다. 마지막으로 비즈니스에 최적화된 기술 스택을 선택할 수 있는데, 예를 들어 어떤 서비스는 Java로 개발하고, 또 다른 서비스는 Node.js로 개발할 수 있는 것이다.

같은 맥락에서 신기술이 나오면 빠르게 적용할 수 있어 혁신을 더 가속화시킬 수 있다.


MSA의 주요 패턴들

MSA에서 서비스간 협업에는 API(Application Program Interface) 방식과 이벤트기반 메시지 방식이 주로 사용된다. API는 주로 동기적 처리를 위한 용도이다. 예를 들어, 주문서비스에서 회원정보가 필요할 때, 회원 ID를 가지고 회원 서비스를 호출하여 정보를 조회한다. 패스(Path)기반 라우팅, 트레픽 제어, 버전관리, 인증, 로깅 등을 처리해주는 요소인 API 게이트웨이가 필요하다.

쿠버네티스 환경에서는 서비스간 통신을 위한 서비스 메쉬 같은 것도 있다. 이벤트 기반 메시지는 비동기 또는 독립적 처리를 위한 용도이다. 예를 들어, 주문이 발생하면(신규 주문 이벤트가 발생하면) 주문 정보를 가진 메시지를 발행하고, 재고 서비스나 앱 푸시 서비스에서 해당 메시지를 구독하여 후속 처리를 한다. 주문 서비스에서는 이벤트 메시지를 발행하는 것으로 자기 할 일이 끝나는 것이다.

API와 이벤트 메시징
API와 이벤트 메시징

이벤트의 경우 사용 패턴에 따라 큐(Queue)와 토픽(Topic)방식으로도 나뉜다. 큐는 입력된 순서에 따라 처리되어야 할 때 주로 사용되며, 한번 소비된 메시지는 큐에서 삭제가 된다. 반면, 토픽은 동일한 이벤트 메시지를 필요한 곳마다 가져다 쓸 수 있는 구독 방식이다. 큐와 토픽 방식을 조합하여 워크 플로우를 만들수도 있다.

큐(Queue) 방식과 토픽(Topic) 방식
큐(Queue) 방식과 토픽(Topic) 방식

MSA에서는 데이터의 변경(생성, 수정, 삭제)과 조회를 분리하는 CQRS(Command Query Responsibility Segregation)패턴도 많이 사용된다. 예를 들어, 주문 조회 서비스에서는 주문, 배송, 회원, 상품 등의 정보를 필요로 한다. 각각의 서비스를 호출하여 데이터를 모아 보여준다면 시간이 오래 걸리고 고객 경험도 나빠진다.

각 서비스에서 데이터 변경이 있을 때마다 발행된 메시지를 주문 조회 서비스에서 수신한 뒤, 하나의 문서로 만들어 사용하면 매번 각 서비스를 호출하지 않고도 빠르게 동일한 기능을 제공할 수 있다. 데이터 상태에 따른 시간차는 발생하지만 대개 수 초 이내가 되고, 최종적으로는 데이터의 일관성이 달성된다.

CQRS 패턴
CQRS 패턴

데이터베이스는 서비스마다 별도로 운영하는데, 스키마가 단순해지고, 중앙집중식 데이터베이스에서 발생하는 경합이나 테이블 잠금 현상이 사라진다. 무엇보다 모놀리식에서 많이 사용되는 관계형 데이터베이스 외에도 목적에 맞는 다양한 타입의 데이터베이스를 사용한다.

예를 들어, 앞서 설명한 주문 조회 서비스는 관계형 데이터베이스보다는 NoSQL타입이 더 나은 선택이 될 것이다. 이 외에도 키-값(Key-Value), 인메모리(In-memory), 그래프(Graph), 원장(Ledger) 등 다양한 타입의 데이터베이스를 활용할 수 있다.

서비스간 트랜잭션이 묶여서 처리되어야 할 때도 이벤트 방식이 사용되는데, 여기서는 가장 유명한 두 가지의 SAGA 패턴을 설명하겠다.

하나는 선행 서비스의 메시지를 후속 서비스가 수신하여 처리해가는 방식이다. 마지막에 위치한 서비스까지 처리가 완료되면 전체적인 분산 트랜잭션이 완료되는 방식이다. 트랜잭션이 실패하면 보상 메시지로 발행하여 선행 서비스가 적절히 처리될 수 있도록 구성한다.

또 다른 패턴은 전체적인 트랜잭션을 관장하는 오케스트레이터(Orchestrator)를 두는 방식이다. 오케스트레이터는 각 서비스에서 수신할 이벤트 메시지를 발행하고, 각 서비스에서 처리 후 발행한 응답 이벤트를 수신하여 전체 처리 완료를 판단한다. 특정 서비스에서 장애가 발생하면 오케스트레이터가 다른 서비스에서 알 수 있도록 메시지를 발행한다.

지금까지 설명한 패턴들 외에도 다양한 패턴이 존재하며, 비즈니스에 적합한 패턴을 적용하는 것이 중요하다.

코레오그래피 사가 패턴과 오케스트레이션 사가 패턴

MSA로의 전환

기존 시스템을 한 번에 MSA로 전환하는 방법도 있지만, 대부분 전문가들은 점진적인 전환을 권장한다. 중요도가 낮거나 복잡하지 않는 모듈을 먼저 MSA로 구현하면서, 그 과정에서 겪게 되는 시행착오들이 조직의 MSA와 애자일 성숙도를 높여준다.

실제 국내 대기업이나 금융권에서도 대부분 이 방식을 사용한다. ‘결합은 느슨하게, 응집도는 높게’라는 시스템 개발 진리는 서비스를 나누는 기준으로도 사용된다. 최근에는 도메인 주도 설계(DDD, Domain Driven Design) 방식이 MSA 설계에서 가장 선호되며, 이벤트 스토밍(Event Storming)과 같은 워크샵도 많은 주목을 받고 있다. 전통적인 방식과 다른 점은 도메인 전문가와 개발조직이 함께 설계에 참여하여 비즈니스 중심의 설계를 하게 된다는 것이다.


애자일 문화로 전환

시스템과 함께 조직도 비즈니스 환경에 민첩하게 대응할 수 있는 애자일 조직으로 거듭나야 한다. 시스템은 MSA인데 일하는 방식이 여전히 폭포수 방식이라면, 그 시스템은 MSA의 장점을 전혀 살리지 못하게 된다.

애자일 방식은 비즈니스 변화에 따른 요구사항 변경에 매우 포용적이다. MSA와 잘 맞는 애자일 방법들 중, 스프린트(Sprint)라는 일정 주기마다 일정량 동작하는 기능을 배포하는 스크럼(SCRUM) 방식이 널리 사용된다. 제품 책임자(Product Owner)는 시스템 요구사항이라 할 수 있는 제품 백로그(Product Backlog)를 우선순위에 따라 정렬시키고, 개발팀은 우선순위가 높은 제품 백로그를 일정량 가져다가 스프린트를 계획하고 개발한다. 백로그의 완료 기준은 통상 ‘동작’ 여부로 판단한다.

즉, 매 2~3주의 스프린트마다 새롭게 동작하는 기능을 배포할 수 있다는 의미가 된다. 폭포수 방식에서는 수 개월이 지나야 가능한 일이 매 스프린트마다 일어나는 셈이다. 비즈니스의 변화가 발생할 때마다 백로그나 우선순위를 변경할 수 있어 민첩하게 대응할 수 있다. 스프린트가 끝나면 개발팀은 회고 시간을 가짐으로 자신들의 일하는 방식에 대해 개선할 점이 없는지를 되돌아 보게 된다.

이러한 장점을 극대화하기 위해 초기에는 최소 기능 제품(MVP, Minimum Viable Product) 위주로 개발하게 되며, MVP가 완성되면 곧바로 비즈니스를 시작한다. 이후 스프린트가 거듭되면서 여러 기능들이 추가된다. 시장이나 고객의 반응을 보면서 제품 백로그를 다시 정렬할 수 있고, 불필요한 기능의 개발을 최소화할 수 있는 장점이 있다.

스크럼, scrum.org
스크럼, scrum.org

통상 서비스와 팀을 1:1로 운영해야 한다고 이야기하지만, 실제 현실에서는 그만한 조직력을 갖추기가 쉽지 않다. 7명 내외의 소규모 팀으로 구성하되, 한 팀이 복수의 서비스를 담당하는 것도 고민해봐야 한다. 단, 이러한 구조적인 한계 속에서도 특정 서비스별 담당자를 지정하지 않는 것을 권장한다. 팀 내의 의사소통은 상호존중 속에서 수평적으로 이루어져야 한다. 직급이 높거나 연차가 높은 것은 중요하지 않으며, 팀이 비즈니스가 원하는 기능을 높은 품질로 생산해내는 것이 중요하다. 시니어의 노련함과 주니어의 창의력이 시너지 효과를 낼 수 있도록 팀 운영에 신경 써야 한다.

장애가 발생했을 때도, 코드를 작성한 사람을 찾기 보다는, 문제의 원인이 무엇이고, 어떻게 해결할 것이며, 재발방지를 위한 방안을 마련하는 데 집중해야 한다.


개발문화의 변화

MSA에서는 모놀리식과 달리 각 서비스별로 개발부터 운영까지 별도의 수명주기를 가지며, 다른 부서의 개발 일정에 영향을 받지 않기 때문에 전체적인 리드타임이 매우 짧다. 민첩성과 함께 서비스의 높은 품질을 유지하기 위해서 몇 가지 지켜져야 할 것들이 있다.

가장 먼저 모델링이다. 복잡한 시스템의 특징들을 표현한 모델은 서비스의 유지보수 뿐만 아니라 타 부서와 협업할 때도 유용하다. 다이어그램은 UML과 같은 표준을 사용하되, 과도한 문서화가 되지 않도록 주의한다.

두 번째는 코드 관리이다. 코드는 언제, 누가, 어떤 이유로 수정되었는지를 추적할 수 있어야 한다. Git과 같은 툴을 사용하여 관리하고, 코드 커밋(Commit)시 코멘트를 충실히 입력해야 한다. 만약 JIRA와 같은 티켓 시스템을 사용한다면 티켓 번호를 넣는 것도 좋다.

세 번째로 코드는 반드시 동료들에게 리뷰(Review)되어야 한다. 코드 리뷰를 통해 비즈니스 요구사항과 로직을 공유하고 점검 받을 수 있다. 더 좋은 알고리즘이나 해법들이 이 과정에서 제시되며, 팀의 코딩 컨벤션도 지속적으로 업데이트 할 수 있다. 무엇보다 문제 상황이 발생해도 이미 팀 내에 코드가 공유되었기 때문에 코드 작성자가 아니더라도 대처가 가능하다.

네 번째로 테스트 코드 없이 머지(Merge)되어서는 안된다. 테스트 코드는 수정된 코드가 잘 동작 하는지와 코드의 임팩트를 점검할 수 있는 중요한 요소다. 테스트 코드가 없거나 커버리지가 너무 낮으면 절대 머지되거나 빌드(Build)되어서는 안된다. 툴을 사용하여 커버리지를 체크하고 커버리지가 낮은 경우 빌드가 실패하도록 구성할 수 있다.

마지막으로 팀 매니저가 개발에 적극적으로 참여하지 못하는 상황이라면 머지의 권한을 팀에 일임하는 것도 고려할만 하다. 비즈니스 로직과 코드를 모르는 매니저가 머지 권한만 가지고 있는 것은 빠른 빌드와 배포에 오히려 방해가 될 수 있다.


빌드와 배포의 변화

MSA 환경에서는 빌드와 배포를 컨테이너로 하는 것이 일반적이다. 컨테이너는 코드, 런타임, 필요한 각종 라이브러리, 환경설정 등을 패키징하는 가상화 기술이다. 컨테이너 이미지에는 애플리케이션 실행에 필요한 모든 것이 있기 때문에 어떤 환경에서도 동일한 동작을 가능하게 해준다. 각 스테이지마다 서버들의 운영환경이 미세하게 달라 발생하는 오류들을 제거할 수 있다. 서비스가 작을 때는 컨테이너 수도 적어서 수동으로 관리할 수 있지만, 그 수가 많아지면 관리에도 많은 리소스가 들어간다. 이를 위해 컨테이너 오케스트레이션 툴들을 사용하게 되는데, 최근에는 쿠버네티스(Kubernetes)가 표준처럼 자리잡았다.

쿠버네티스 구성요소, https://kubernetes.io/docs/concepts/overview/components/
쿠버네티스 구성요소, https://kubernetes.io/docs/concepts/overview/components/

모놀리식 아키텍처에서는 배포의 단위가 크기 때문에 롤링 업데이트 방식이 주로 사용되지만, 컨테이너 기반의 MSA환경에서는 블루/그린(Blue/Green) 방식과 카나리(Canary) 배포가 주로 사용된다.

블루/그린 배포는 신규 버전(그린)을 먼저 배포하고 정상동작이 확인되면 트래픽의 유입을 신규버전으로 스위치 시키는 방식이다. 카나리 배포는 신규 버전을 일부 배포한 뒤, 소량의 트래픽을 신규 버전으로 흘러가게 한다. 신규 버전의 정상동작이 확인되면 배포 리소스와 트래픽을 늘려가면서 최종적으로는 기존 버전으로의 트래픽을 모두 차단하는 방식이다.

두 방식 모두 기존 버전의 리소스는 삭제하면 된다. 컨테이너 이미지는 여전히 존재하기 때문에 이전 버전으로 돌아가는 것도 어렵지 않다. 컴퓨팅 리소스를 탄력적으로 운영할 수 있는 클라우드 환경에서 각광받는 방식이기도 하다.

블루/그린 배포와 카나리 배포
블루/그린 배포와 카나리 배포

클라우드나 컨테이너 환경에서 각 서비스에는 오토스케일링(Auto-Scaling)을 적용한다. 트래픽의 많고 적음에 따라 투입되는 서버나 컨테이너를 조절할 수 있어 탄력적인 운영이 가능해진다. 비정상 동작을 하는 컨테이너는 즉시 삭제하고, 신규 컨테이너를 띄우면 되기 때문에 복원력도 매우 높다.

데브옵스(DevOps)환경에서는 개발부터 운영까지 전 과정을 최대한 자동화 해 개발팀이 비즈니스에 집중할 수 있게 해주어야 한다. 이러한 체계를 갖추기 위해서는 통상적으로 여러 툴을 사용해야 하기에 관리의 어려움이 발생할 수도 있는데, 이를 해결하기 위해 퍼블릭 클라우드 서비스를 활용하는 것도 좋은 방법이다.


결론

아마존, 구글, 넷플릭스 등 글로벌 선진 기업들은 2000년대부터, 국내 유수의 선진 기업들도 2010년대부터 MSA와 애자일을 도입하여 성장해왔다. 비즈니스 환경이 보다 빠르게 변화하고, 고객의 요구사항이 한층 다양해지는 상황에서 전통적인 모놀리식 아키텍처와 폭포수 방식으로 대응한다면 시장에서 도태되는 것은 시간문제다. 판이 바뀌고 있다. 바뀐 판에서는 더 진화된 아키텍처인 MSA와 애자일한 업무 방식으로 대응해야 한다.

저작권자 © 컴퓨터월드 무단전재 및 재배포 금지