마이크로서비스 아키텍처 (크리스 리차드슨)
This a translation of an article Microservices Architecture originally written and copyrighted by Chris Richardson.
이글은 Chris Richardson가 작성하였으며, 저작권을 가지고 있는 Microservices Architecture 글의 번역본입니다.
맥락 (Context)
서버 사이드 기업용 애플리케이션 개발을 하고 있다고 해보자. 데스크탑 브라우저와 모바일 브라우저, 그리고 네이티브 모바일 애플리케이션을 포함해 여러 가지 다양한 클라이언트 지원해야만 한다. 또한, 애플리케이션은 3rd 파티가 사용할 수 있도록 API를 노출해야 할 수도 있다. 또한 웹서비스나 메시지 브로커를 통해서 다른 애플리케이션 서비스와 통합해야 할 수도 있다. 애플리케이션은 비즈니스 로직을 실행하고, 데이터베이스에 접근하며, 다른 시스템들과 메시지를 주고받아 HTML/JSON/XML 응답을 돌려주는 것으로 요청(HTTP 요청과 메시지)을 처리한다
애플리케이션은 계층형 아키텍처나 6방형(hexagonal) 아키텍처를 갖거나 다양한 유형의 컴포넌트로 구성되어 있다.
- 프리젠테이션 컴포넌트- HTTP 요청을 제어해서 HTML이나 JSON/XML(웹서비스 API들로써)로 응답을 보내는 책임
- 비즈니스 로직- 애플리케이션의 비즈니스 로직
- 데이터베이스 접근 로직 - 데이터베이스에 접근해서 데이터 접근 객체 만드는 책임
- 애플리케이션 통합 로직 - 메시지 처리 레이어를 말하며, Spring Integration을 기반으로 하는 걸 예로 들 수 있음
이들은 애플리케이션의 다양한 기능적인 측면에 상응하는 논리적인 컴포넌트이다.
문제 (Problem)
애플리케이션의 배포 아키텍처는 어떤 것인가?
영향도 (Forces)
- 애플리케이션을 개발하는 개발자들의 팀
- 새로운 팀원은 빠르게 생산성을 보여줘야 함
- 애플리케이션은 쉽게 이해하고, 수정할 수 있어야 함
- 애플리케이션의 지속적인 배포가 관례화 되기를 기대함
- 규모가변성(Scalability) 와 가용성(Availability) 요구사항을 만족하기 위해서 다수의 장비에서 애플리케이션의 다수의 복사본이 실행되야 함
- 최근 부각된 기술(프레임워크, 프로그래밍 언어 등)을 기회로 활용되기를 원한다.
해결방법 (Solution)
Scale Cube(특히 Y-축 스케일 확보)를 적용해 애플리케이션 아키텍처를 수립하고, 기능적으로 애플리케이션을 서비스 조합의 집합으로 분해한다. 각 서비스는 제한적으로 관련된 기능의 집합을 구현한다. 예를 들어, 하나의 애플리케이션은 주문 관리 서비스, 고객 관리 서비스 등과 같은 서비스로 구성할 수 있다.
서비스는 HTTP/REST와 같은 동기방식 프로토콜을 사용하거나 AMQP와 같은 비동기 방식 프로토콜을 사용해 상호소통을 한다.
서비스는 서로 간에 독립적으로 개발되고 배포된다.
각 서비스는 다른 서비스와 분리하기 위해서 자신의 데이터베이스를 갖는다. 필요할 때 데이터베이스 간의 일관성은 데이터베이스 복제 매카니즘이나 애플리케이션 수준의 이벤트를 사용해 관리한다.
예시
고객에서 주문까지, 재고(inventory)를 확인하고, 신용결재(credit)가 가능하며, 이를 출하(ships)할 수 있는 전자 상거래 애플리케이션을 구축한다고 상상해보자. 애플리케이션은 신용거래를 확인하고, 재고를 관리하고, 주문을 출하하는 백 엔드 서비스와 함께 사용자 인터페이스를 구현하는 StoreFrontUI를 포함하는 각각 컴포넌트로 구성한다.
애플리케이션은 서비스 집합으로 배포한다.
상황 해결하기
이 해결방법에는 여러 장점이 있다.
- 각 마이크로서비스는 상대적으로 크기가 작다
- 개발자들이 이해하기 더 쉽다. IDE는 개발자들이 더 생산적으로 빠르게 개발하게 해준다.
- 웹 컨테이너는 더 빠르게 시작할 수 있고, 이는 개발자들의 생산성을 높여주고, 배포를 빠르게 해준다.
- 각 서비스는 다른 서비스와 독립적으로 배포할 수 있다 – 빈번하게 서비스의 새로운 버전을 배포하기 더 쉽다.
- 개발 스케일 확보가 더 쉽다 – 여러 팀으로 개발 노력을 조직화 할 수 있다. 각 팀(2개 피자)은 단일 서비스에 대한 책임을 진다. 각 팀은 다른 모든 팀들과 독립적으로 서비스를 개발하고, 배포하고, 스케일을 확보할 수 있다.
- 잘못된 점을 고립시킬 수 있다. 예를 들어, 하나의 서비스에서 메모리 누수가 발생하면 해당 서비스에만 영향을 줄 것이다. 다른 서비스는 계속해서 요청을 처리할 수 있다. 이것과 비교해 모놀리틱 아키텍처에서 하나의 컴포넌트가 잘못 돌아가게 되면 전체 시스템 다운될 수 도 있다.
- 각 서비스는 독립적으로 개발하고, 배포할 수 있다.
- 기술 스택에 대한 장기간 위임(역. 오랫동안 유지되어 쉽게 변경할 수 없었던 기술 스택)을 제거할 수 있다.
이 해결책은 다음과 같은 단점이 있다.
- 개발자는 분산 시스템을 만들기 위해 추가되는 복잡도를 다뤄야만 한다.
- 개발툴/IDE는 모놀리틱 애플리케이션을 구축하는 것에 기원을 두고 있고, 분산 애플리케이션 개발은 명시적으로 지원하지 않는다.
- 테스트가 더 어렵다
- 개발자는 서비스 상호 간의 커뮤니케이션 매카니즘을 구현해야 한다
- 어려운 분산 트랜잭션을 사용하지 않고 다수의 서비스로 확대하는 유스케이스를 구현해야 한다
- 배포가 복잡하다. 실 환경에서 또한 배포 운영의 복잡성과 매우 다양한 서비스 유형으로 구성된 시스템을 관리 해야 한다.
- 메모리 소비량 증가 – 마이크로서비스 아키텍처는 N 모놀리틱 애플리케이션 인스턴스를 N x M 서비스 인스턴스로 교체한다. 각 서비스가 일반적으로 인스턴스를 고립시켜야 하는 필요에 따라 자신의 JVM(또는 이에 상응하는)에서 실행한다면 JVM 런타임 개수만큼 M배의 비용이 든다. 게다가 Netflix 경우처럼 각 서비스가 자신의 VM(이를 테면 EC2 인스턴스)에서 실행한다면 비용은 훨씬 더 많이 든다.
이 접근 방법을 사용하려고 할 때 겪는 첫 번째 도전은 이 방법을 사용하기에 적절한지에 따라 판가름이 난다. 애플리케이션의 첫 번째 버전을 개발하는 시기에는 이 접근 방법이 해결해 주는 문제를 대부분 겪고 있지 않을 것이다. 게다가 분산 아키텍처를 정교하게 사용할수록 개발 속도가 늦어진다. 이 점이 시작할 때 가장 큰 문제가 되며, 대부분 빠르게 발전하는 비즈니스 모델에 맞춰서 얼마나 애플리케이션을 만들어 가는 지가 가장 큰 도전 과제다. Y 축을 사용해 빠르게 반복하는 것이 더 어렵다고 할 수 있다. 그렇지만 향후에 도전 과제가 어떻게 스케일을 확보하고 기능 분해를 사용할 필요해 지면, 엉망이 된 의존성은 모놀리틱 애플리케이션을 서비스의 집합으로 분해하는 것이 더 어려울 것이다.
또 다른 도전 과제는 어떻게 시스템을 마이크로서비스로 분할(partition)할 건지 결정하는 것이다. 이건 매우 예술적인 일이지만 도움이 되는 몇 가지 전략이 있다. 첫 번째 방법은 동사와 유즈 케이스로 서비스를 분할하는 것이다. 예를 들어, 향후 분할된 전자 상거래 애플리케이션은 출하 완료 주문에 대한 책임을 출하 서비스(Shipping service)가 갖는 것을 생각해 볼 수 있다. 또 다른 동사로 분할한 흔한 예로 로그인 유즈 케이스를 구현한 로그인 서비스를 들 수 있다.
또 다른 분할 접근 방법은 명사와 리소스로 시스템을 분할하는 방법이다. 이러한 서비스의 유형은 해당 타입의 엔티티/리소스의 모든 연산에 대한 책임을 진다. 예를 들어, 향후 상품 재고가 있는지 추적하는 재고 서비스(Inventory service)를 제공하는 전자 상거래 시스템의 의미를 생각해 볼 수 있다.
이상적으로는 각 서비스가 작은 책임의 집합으로만 되어 있어야 한다. (Uncle Bob이라 불리는) 밥 마틴은 단일 책임 원칙(SRP, Single Responsible Principle)을 사용해 클래스를 설계하라고 얘기한다. SRP는 변경의 이유에 따라서 클래스의 책임을 정의하며, 이 때 클래스에는 반드시 변경 원인이 하나만 있어야 한다. 서비스 설계 시에 SRP 또한 적용해보는 것 또한 의미가 있다.
또 다른 서비스 설계에 도움이 되는 유사점은 유닉스(Unix) 유틸리티 설계에서 볼 수 있다. 유닉스는 grep, cat, find와 같은 매우 많은 수의 유틸리티를 제공한다. 각 유틸리티는 정확히 하나이며, 종종 복잡한 작업을 수행하기 위해 특별히 쉘 스크립트를 사용해 다른 유틸리티와 잘 조합될 수 있다.
관련 패턴
모놀리틱 아키텍처와 대체 가능한 패턴이다.
쓰임새
Netflix, Amazon, eBay를 포함해 대부분 대규모 웹 사이트는 모놀리틱 아키텍처에서 마이크로서비스 아키텍처로 발전해 왔다.
인터넷 트랙픽의 30%까지 책임지는 가장 유명한 비디오 스트리밍 서비스 회사인 Netflix는 대규모 서비스 지향 아키텍처(service-oriented architecture)이다. 이들은 비디오 스트리밍 API로 매일 800개가 넘는 디바이스에서 오는 백만 번 이상의 호출을 처리한다. 각 API 호출은 평균적으로 백 엔드 서비스의 6번 호출로 전개된다.
Amazon.com은 본래부터 2-티어 아키텍처였다. 스케일 확보를 위해 수백 개의 백 엔드 서비스로 구성되는 서비스 지향 아키텍처로 이동했다. 몇몇 애플리케이션은 Amazon.com 웹사이트와 웹서비스 API를 구현하는 애플리케이션에 들어가 있는 서비스를 호출한다. Amazon.com 웹 사이트 애플리케이션은 웹 페이지를 구성하는 데 사용하는 데이터를 얻기 위해 100~150개 서비스를 호출한다.
경매 사이트인 ebay.com 역시 모놀리틱 아키텍처에서 서비스 지향 아키텍처로 발전해나갔다. 애플리케이션 티어는 다수의 독립적인 애플리케이션으로 구성되어 있다. 각 애플리케이션은 구매나 판매처럼 특정 기능 영역에 대한 비즈니스 로직을 구현한다. 각 애플리케이션은 X-축 분해를 사용하고, 검색과 같은 일부 애플리케이션은 Z-축 분해를 사용한다. 또한, ebay.com은 X-, Y-, Z- 스타일의 스케일 확보 방법을 조합해 적용했다.