Microservices on AWS

글쓴이 상배 윤 날짜

원문 : Introduction Microservices on AWS

마이크로서비스는 배포주기를 가속화 하고 응용 프로그램의 유지 관리성을 높여서 높은 품질의 제품을 만들기 위한 아키텍처 모델이다. 이 접근법은 개발방법 뿐만 아니라 소프트웨어와 서비스를 제공하는 조직의 변화도 포함하고 있다. 마이크로 서비스의 접근방식을 사용하는 소프트웨어는 잘 정의된 API로 통신하는 작고 독립적인 소프트웨어 컴포넌트들로 구성된다.

이 백서는 마이크로서비스의 일반적인 특징을 요약하고, Amazon Web Serivces(AWS)위에서 어떻게 마이크로서비스 아키텍처를 구성할 수 있는지를 다룬다.

소개

지난 몇년 동안 마이크로서비스는 IT 아키텍처의 중요한 흐름이었다. 마이크로서비스 아키텍처는 완전히 새로운 소프트웨어 엔지니어링 접근 방법이 아니다. 마이크로서비스는 애자일 소프트웨어 개발 방법론과 Service-oriented architecture(SOA), API-first 디자인, Continuous Delivery(CD)와 같은 다양한 디자인 패턴들의 장점을 채용해서 만든 아키텍쳐다. The Twelve-Factor App에 정의된 패턴들이 마이크로 서비스에서 사용하고 있다.

마이크로서비스의 특징

  • 탈중앙 – 마이크로서비스 아키텍쳐는 탈중앙화된 데이터를 관리하는 분산시스템이다. 이들은 중앙에 있는 통일된 데이터베이스에 의존하지 않는다. 각 마이크로 서비스는 자신의 데이터모델과 뷰를 가지고 있다. 또한 마이크로서비스는 개발, 배포, 관리, 운영까지 분산 수행한다.
  • 독립적 – 마이크로서비스를 구성하는 다양한 구성요소들은 다른 구성요소들에 영향을 주지 않고 독립적으로 수정, 업그레이드, 교체 작업을 수행한다. 마찬가지로 각 컴포넌트를 담당하는 팀은 서로 독립적으로 행동 할 수 있다.
  • 한 가지를 잘 수행한다. – 각 마이크로서비스 컴포넌트들은 특정 도메인의 업무를 잘 처리하도록 설계된다. 만약 특정 서비스의 구성요소가 여러 도메인에 걸쳐서 너무 많은 기능을 가지고 있을 때는 두 개 이상의 서비스로 나눌 수 있다. 마이크로서비스는 가능한 코드의 복잡도를 낮추는 방법을 찾는다.
  • 폴리글랏(Polyglot) – “누구에게나 다 맞는(one size fits all)”을 따르지 않는다. 팀은 문제의 해결에 가장 적합한 도구를 선택할 자유가 있다. 결과적으로 마이크로서비스는 운영체제, 프로그래밍언어, 데이터저장소 기타 도구들에 대해서 다양한 접근법을 취한다.
  • 블랙박스 – 마이크로서비스의 각 구성요소는 복잡성을 숨기기 위해서 블랙박스로 디자인된다. 서비스간의 모든 통신은 숨겨진 종속성과 암시를 방지하기 위해서 잘 정의된 API를 통해서 이루어진다. 마이크로서비스에서는 특히 잘 정의된 API와 문서화가 매우 중요하다.
  • 만든 사람이 실행한다. : 일반적으로 서비스를 개발하는 팀이, 운영과 관리까지를 함께 한다. 이 원칙은 DevOps라고 알려져 있다. 개발자는 실제 소프트웨어 사용자와 긴밀하게 접촉하고 고객에 대한 이해를 높이며, 이러한 이해를 이를 소프트웨어에 반영한다. Conways 법칙 (모든 시스템은 그 조직의 의사소통 구조와 동일하게 만들어진다)에 따라서, 마이크로서비스 아키텍처를 제대로 실행하기 위해서는 조직도 DevOps처럼 운영되어야 한다.

마이크로 서비스의 장점

많은 AWS 고객들은 전통적인 모노리틱 아키텍처에서 경험했던 민첩성, 확장성의 어려움을 해결하기 위해서 마이크로서비스를 선택한다. 여기에서는 마이크로서비스를 선택함으로서 가질 수 있는 장점들을 살펴보겠다.

민첩성

마이크로서비스는 그들의 서비스들에 대해서 독립적인 권한을 행사할 수 있는 조직을 만든다. 팀은 맥락을 잘 이해할 수 있으며, 그들이 잘 할 수 있는 작은 업무들을 맡아서 독립적으로 수행한다. 이러한 업무들은 식속하게 수행할 수 있으며, 개발에서 배포까지의 사이클을 극적으로 단축한다. 결과적으로 조직의 총 처리량이 향상된다.

아래 그림은 마이크로서비스와 모노리틱서비스의 개발 방법을 묘사하고 있다.

혁신

자유롭게 움직이며 자신들이 맡고 있는 도메인에 적합한 기술과 프레임워크 그리고 툴을 선택할 수 있다는 사실은 혁신의 주 원동력이 된다.

하나의 조직에서 개발과 운영 기술을 통합해서 만든 DevOps 문화는 분리된 조직간의 커뮤니케이션 과정에서 생길 수 있는 마찰과 모순을 제거한다.

애자일 프로세스는 배포를 위해서 중단하지 않는다. 대신에 커밋에서 코드의 실행까지 전체 응용 프로그램의 수명주기를 Continuous Delivery 과정에 녹아내고 자동화 할 수 있다. 이것은 새로운 아이디어를 신속하게 테스트 하고 작동하지 않을 경우 빠르게 롤백할 수 있도록 한다. 낮은 실패 비용은 변화와 혁신의 문화를 창출한다.

품질

마이크로 서비스를 중심으로 소프트웨어 엔지니어링을 조직하면 코드의 품질을 높일 수 있다. 소프트웨어를 작고 잘 정의된 모듈로 나눔으로서 얻을 수 있는 이점은 객체지향 소프트웨어를 적용함으로써 얻는 이득과 비슷한 측면이 있다. 즉 재사용성, 유지 관리성, composability를 얻을 수 있다.

마이크로서비스의 세분화된 디커플링은 대규모 시스템을 구축하기 위한 최상의 방법이다. 특정 서비스에 적당하고 최적화된 기술을 선택할 수 있기 때문이다. 각 서비스는 적당한 프로그래밍 언어 및 프레임워크 그리고 최적화된 데이터 베이스를 선택할 수 있으며, 최상의 성능을 위해서 세밀하게 옵션을 설정 할 수 있다.

적절하게 디커플링된 서비스는 수평적으로 그리고 독립적으로 확장할 수 있다. 거대한 단일 머신에서 이루어지는 수직 스케일링은 개별 서버의 용량에 제한되며, 스케일링 도중에 다운타임을 생길 수 있다. 수평적 확장은 기존의 서버 풀에 더 많은 서버를 추가흐는 것만으로 개별 서버의 한계를 뛰어넘어서 확장 할 수 있다. 이러한 스케일링 작업은 완전히 자동으로 수행 할 수 있다.

또한 실패한 컴포넌트를 쉽게 그리고 자동으로 대체 할 수 있기 때문에 견고한 애플리케이션을 만들 수 있다.

가용성

마이크로서비스 아키텍처는 장애로부터 격리된 서비스를 더 쉽게 만들 수 있다. 상태검사(health check), 캐싱, bulkhead, circuit breakers와 같은 기술들을 이용해서 구성요소의 실패가 서비스 전체로 확산되는 걸 막는다.

마이크로서비스의 과제

다른 모든 아키텍처와 마찬가지로 마이크로서비스도 고유의 단점을 가지고 있다. 여기에서는 마이크로서비스의 문제점과 절충할 수 있는 방법들을 살펴보려 한다.

  • 분산시스템: 마이크로서비스는 그 자체가 분산시스템이다. 분산 시스템은 종종 Fallacies of Distributed Computing라는 문제가 나타난다. 분산시스템에 익숙하지 않은 개발자는 “네트워크는 안정적이고 대기시간은 0이며, 대역폭은 무한하다고” 생각하고 시스템을 개발하는 경우가 있다.
  • 마이그레이션: 모놀리틱 아키텍처에서 마이크로서비스 아키텍처로 이전하는 건 쉬운일이 아니다. 코드의 종속성을 데이터베이스 종속성으로 바꾸는 까다로운 작업을 거쳐야 한다.
  • 버전: 모놀리틱 아키텍처는 단일 서버 애플리케이션의 버전만 관리하면 된다. 마이크로서비스는 분리된 각각의 컴포넌트들의 버전을 관리해야 한다. 때때로 API 단위로 버전을 관리해야 할 수 있는데, 다양한 모범사례와 패턴들을 조사해야 한다.
  • 조직: 마이크로서비스 아키텍처를 수행하기 위해서는 조직도 그에 맞게 아키텍처링되야 한다. 조직은 DevOps 접근방식을 따르도록 구성을 변경해서 개발과 운영간의 의사소통을 간소화하기 위한 방법을 찾아야 한다.
    이 문서(백서)는 마이크로서비스 아키텍처로 전환 할 때의 개발과 운영에 중점을 둔다. AWS에서의 DevOps에 대한 내용은 https://aws.amazon.com/devops/ 문서를 참고하자.

아키텍처의 복잡도 증가

모노리틱아키텍처의 복잡성과 종속성의 수는 코드안에 존재한다. 반면 마이크로서비스 아키텍처는 도메인을 구성하는 각 서비스들의 상호작용이 증가하는 즉 ”’구조적으로 복잡도가 증가하는”’양상을 보인다.

비동기 통신, 계산식 오류, 데이터 일관성, 서비스 검색, 인증과 같은 것들은 마이크로서비스 아키텍처야 해결해야 할 주요 과제들이다.

운영 복잡도의 증가

마이크로서비스에서 당신은 하나의 서비스를 운영하는 대신, 수십에서 수백개의 서비스를 운영하게 될 것이다. 이것은 아래와 같은 여러가지 이슈를 불러일으킨다.

  • 어떻게 리소스를 저렴한 비용으로 확장성있게 전개할 수 있을까 ?
  • 어떻게 수십에서 수백개의 마이크로서비스 구성요소를 적은 노력으로 작동시킬 수 있을까 ?
  • 여러 팀에서 개발되는 중복된 코드와 툴들을 어떻게 관리해야 할까 ?
  • 수백 가지 코드의 배포와 상호의존성을 어떻게 추적할 수 있을까 ?
  • 분산된 환경에서 시스템 전체를 모니터링하고, 잠재된 문제를 미리 식별할 수 있을까.
  • 분산 시스템을 추적하고 디버깅하는 방법
  • 어떻게 분산된 컴포넌트들이 만들어내는 대량의 로그를 분석 할 수 있을까 ?
  • 어떻게 다양한 기술을 가진 사람들과 다양한 기종을 포괄하는 표준을 만들 수 있을까 ?
  • 기술은 계속 변할 것이고 다양성도 늘어날 것이다. 시간이 지나더라도 다양성을 유지하면서, 잘 유지되고 업그레이드 될 수 있는 시스템을 만들어야 한다.
  • 버전관리는 어떻게 할 것인가 ?
  • 서비스의 적절한 분리와 서비스간의 통신 품질 보장.

마이크로서비스와 클라우드

AWS는 마이크로서비스 아키텍처가 가지는 문제점 혹은 과제를 해결 할 수 있는 기능들을 제공한다.

  • 온디멘드(On-demand resources)로 자원 요청 : AWS의 자원은 필요할 때 요청해서 사용 할 수 있으며, 요청 즉시 신속하게 프로비저닝된다. 기존의 인프라와 비교하면 자원 요청에 제한이 없다. 다양한 환경과 다양한 버전의 자원이 일시적으로 혹은 지속적으로공존할 수 있다. 또한 예측하기 어려운 용량산정의 필요가 없다. AWS의 자원은 주문형이기 때문에, 필요한 만큼만 요청해서 사용 할 수 있다.
  • 적은 비용으로 실패(위험)을 경험 할 수 있다. : 새로운 아이디어의 시험에는 위험이 따르며, 많은 비용과 시간을 소비해야 할 수도 있다. AWS를 이용해서 새로운 아이디어, 기능을 배포하고 실험하며 실패하면 바로 종료 할 수 있다. 아이디어를 실험하기 위한 비용과 위험을 줄이는 것은 혁신을 추진하기 위한 핵심적인 요소다. 이것은 민첩성을 높이기 위한 마이크로서비스의 목표에 완벽히 부합한다.
  • 프로그래밍 : AWS 서비스는 다양한 프로그래밍 언어를 위한 SDK, CLI(Command Line Interface), API를 제공한다. 서버 혹은 전체 구조는 프로그래밍 방식으로 복제, 종료, 스케일링(스케일 업/다운, 스케일 인/아웃) 모니터링을 할 수 있으며, 여기에 더해 실패도 자동으로 복구 할 수 있다. 이러한 표준화와 자동화는 속도, 일관성, 반복, 확장성을 위한 핵심 열쇠다. 개발자는 AWS에 제공하는 코드, API 들을 이용해서 서비스를 전개하고 실행하고 운영하는데 필요한 노력을 최소화 할 수 있다.
  • Infrastructure as Code : 프로그래밍된 스크립트를 이용해서 인프라를 프로비저닝하고 관리하는 것에 더해서, AWS는 마치 애플리케이션 코드를 개발하는 것처럼 전체 인프라를 코드로 기술하고 버전을 관리 할 수 있다. 결과적으로 언제든지 특정 버전의 인프라를 재 배포 할 수 있다. 개발자는 특정 애플리케이션의 버전과 인프라의 버전을 비교하면서 최적의 서비스 환경을 유지할 수 있다. 이제 롤백은 애플리케이션에만 국한된게 아니라 전체 인프라에 대해서 수행 할 수 있다.
  • Continuous Delivery : 인프라를 프로그래밍할 수 있으므로 프로비저닝 및 배포 프로세스를 완전히 자동화 할 수 있다. 지속적인 통합(Continuous Integration)은 운영의 일부로 통합될 수 있다. 이를 이용해서 지속적인 배포(Continuous Deployment and Delivery)의 채택이 가능해진다. 지속적인 배포는 다양한 프로그램의 수명 주기를 관리 할 때 발생할 수 있는 복잡도 문제를 해결한다.
  • Managed Services : 관리형 서비스는 클라우드 인프라의 주요 이점이다. 가상 서버의 프로비저닝, 소프트웨어의 설치, 구성 및 최적화, 확장성, 백업 및 복구, 모니터링을 클라우드에 위임함으로서 관리자와 개발자는 부담을 줄일 수 있다. 마찬가지로 관리형 서비스는 마이크로서비스의 복잡도를 낮춰준다.
  • Service orientation : AWS는 그 자체가 서비스 지향 구조를 따른다. 각 AWS 서비스는 자신이 맡은 도메인의 업무를 잘 처리할 수 있도록 최적화 되있다. 또한 이들은 명확하게 정의된 API를 제공하는 것으로 다른 서비스와 통신 할 수 있다. 개발자는 레고(LEGO)블럭을 쌓는 것처럼, 이들 서비스들을 결함해서 복잡한 서비스 인프라를 구성할 수 있다. 이러한 접근 방식은 바퀴의 재발명이라고 부르는 개발과 프로세스에서의 중복을 제거한다.
  • 폴리글랏 : AWS는 다양한 스토리지와 데이터베이스 기술을 제공한다. AWS EC2(Amazon Elastic Compute Cloud)위에서 실행되는 다양한 운영체제에서 사용 할 수 있는 애플리케이션들이 마켓플레이스를 통해서 제공하고 있다. 또한 AWS는 다양한 프로그래밍언어를 지원하는 SDK도 제공한다. 이를 통해서 문제에 가장 적합한 솔류션을 찾을 수 있다.

AWS에서의 마이크로서비스 아키텍처

과거 모놀리틱 애플리케이션은 유저 인터페이스(UI) 레이어 , 비지니스 레이어, persistence 레이어와 같이 레이어를 이용해서 애플리케이션 스택을 쌓았다. 마이크로서비스 아키텍처의 핵심아이디어는 기술의 계층(레이어)가 아니라 특정 도메인을 응집력이 있는 수직으로 분할해서 연결하는데 있다.

User Interface

최신 웹 애플리케이션들은 종종 자바스크립트 프레임워크를 이용해서 RESTFul API로 통신하는 single-page application을 구현한다. 정적 웹 컨텐츠들은 S3(Amazon Simple Storage Service)와 Amazone CloudFront로 서비스한다.

마이크로서비스의 클라이언트는 요청하는 위치에서 가장 가까운 곳에 있는 ”’엣지”’로 부터 서비스를 받으며, 캐시나 프록시 서버로 연결하기 때문에 응답시간을 개선하고 대기시간을 줄일 수 있다.

Microservices

마이크로서비스에서 API는 모든 클라이언트 요청의 중앙 진입지점이다. RESTfual API는 애플리케이션의 로직을 숨기는 역할을 한다. API는 클라이언트의 요청을 받아서 처리하며, 트래픽 관리, 요청 필터링, 리우팅, 캐싱, 인증및 권한부여와 같은 일을 처리한다.

많은 AWS 고객들은 ELB(Elastic Load Balancer)의 Application Load Balance와 EC2 Container Service(Amazon ECS) 그리고 오토스케일링 기능등을 이용해서 마이크로서비스 애플리케이션을 구현한다. Application Load Balancer는 클라이언트 요청의 컨텐츠를 포함하는 애플리케이션 레벨에서의 트래픽 라우팅을 지원한다.

Application Load Balancer는 클라이언트 요청을 ECS 컨테이너 인스턴스로 분배한다.

Amazon ECS 컨테이너 인스턴스는 클라이언트 요청의 갯수 혹은 로드에 따라서 Scale in 혹은 Scale out 할 수 있다. 탄력적인 스케일링은 비용효율적인 시스템의 구성과 서비스 거부 공격에 대한 대응력을 높인다.

EC2로도 이런일들을 할 수 있는데, ECS를 우선 언급하는 이유는 컨테이너 기반으로 배포 하는 것으로 배포에 들어가는 운영비용을 줄일 수 있으며 스케일링도 더 수월하게 할 수 있기 때문이다.

  • Portability – 컨테이너 이미지는 일관적이고 불변하다. 이미지의 실행장소가 유저의 데스크탑이건 빌드 시스템이건 프러덕션 환경이건 동일하게 작동한다.
  • Productivity – 컨테이너는 서비스 종속성과 충돌을 제거해서 개발자의 생산성을 높인다. 각 응응 프로그램의 구성요소는 다른 독립적인 컨테이너로 구성 할 수 있다.
  • Efficiency – 컨테이너가 필요로 하는 자원(CPU, RAM)을 명시적으로 설정할 수 있으므로, 리소스의 사용율을 크게 향상시킬 수 있다. 또한 컨테이너는 가상화된 서버에 비해서 성능 오버헤드가 적으며 운영체제의 리소스를 효율적으로 사용 한다.
  • Control – 컨테이너는 애플리케이션 코드와 종속성을 자동으로 버저닝한다. 도커 컨테이너와 Amazon ECS Task definitions은 컨테이너의 버전을 추적하고 관리 할 수 있게 한다. 필요하면 간단하게 이전 버전으로 롤백할 수도 있다.

AWS ECS를 이용하면 애플리케이션의 설치, 운영, 클러스터링관리를 할 필요가 없다. 간단한 API를 호출하는 것으로 도커를 실행하거나 중단할 수 있으며, 클러스터의 상태를 모니터링하고, 보안그룹, 로드밸런서, 볼륨(EBS)등에 접근 할 수 있다.

Data Store

마이크로 서비스에서 필요한 데이터를 저장하기 위한 데이터 저장소를 선택해야 한다. 세션 데이터는 주로 Memcached 혹은 Redis와 같은 인-메모리(in-memory) 캐시에 저장한다. AWS는 ElastiCache 서비스로 두 개의 기술을 모두 지원한다.

AWS ElastiCache는 인-메모리 데이터 저장소를 쉽게, 배포 및 운용할 수 있도록 도와주는 클라우드 서비스다. 이 서비스는 느린 디스크기반의 데이터베이스대신 메모리에 데이터를 저장해서 웹 서비스의 성능을 향상시킨다.

응용 애플리케이션 서버와 데이터베이스 사이에 캐시를 배치하는 것은 데이터베이스에서의 읽기요청을 줄이는 일반적인 메커니즘이다. 읽기를 캐시가 처리하기 때문에 데이터베이스의 쓰기 성능을 높일 수 있으며, 웹 서비스의 성능을 향상 시킬 수 있다.

관계형데이터베이스(RDBMS)는 구조화된 데이터나 비지니스 정보를 저장하기 위해서 여전히 중요하게 사용하고 있다. AWS는 Amazon RDS(Amazon Relational Database Service)를 통해서, Microsoft SQL Server, Oracle, MySQL, MariaDB, PostgreSQL, Amazon Aurora 등의 주요 데이터베이스 엔진을 제공한다.

Amazon RDS를 이용하면 클라우드 환경에서 손쉽게 관계형 데이터베이스를 실행 할 수 있다. 복잡한 데이터베이스 관리의 대부분을 위임할 수 있다. 사용자는 간단하게 용량을 확장할 수 있으며, 가용성 구성, 자동화된 백업/복구 시스템을 구축 할 수 있다. 이런 복잡한 작업의 대부분을 AWS에 위임함으로써, 사용자는 응용 프로그램의 개발과 비지니스의 구현에 집중 할 수 있다.

그러나 관계형 데이터베이스는 무한으로 늘어나는 데이터를 대상으로 설계되지 않았기 때문에, 많은 수의 쿼리를 지원하는 서비스에 적용이 어려울 수 있다.

NoSQL 데이터베이스는 관계형 데이터베이스에서의 일관성을 희생하는 대신에 확장성, 성능, 가용성을 높이는 방향으로 설계됐다. 또한 NoSQL 데이터베이스가 엄격한 스키마를 필요로 하지 않는 다는 것도 중요한 장점이 될 수 있다. 데이터는 횡적으로 분산배치도며, 파티션 키를 이용해서 빠르게 검색 할 수 있다.

개별 마이크로 서비스는 한 가지 작업을 잘 수행하도록 설계되기 때문에 NoSQL과 같은 단순한 데이터모델을 사용 할 수 있는 데이터베이스 엔진이 선호된다. 다만 NoSQL을 선택할 때 주의해야 할 점이 있는데, NoSQL은 관계형 데이터베이스가 가지고 있는 테이블 조인 등의 기능이 아예 없거나 제한적인 경우가 많다. 이러한 기능이 필요한 경우 응용 애플리케이션에서 구현해야 한다. 때때로 지나치게 복잡해져서 응용 애플리케이션의 개발이 어려워지는 경우가 있는데, 이 때는 RDBMS를 선택하는게 더 나을 수 있다.

Amazon DynamoDB는 규모에 상관없이 수 밀리초의 대기시간단에 데이터 접근을 필요로 하는 애플리케이션에 사용 할 수 있는 NoSQL 데이터베이스 서비스다.

Reducing Operational Complexity

아마도 여러분들은 EC2 인스턴스 기반의 아키텍처를 사용하고 있을 것이다. 여기에서는 서버리스(Serverless) 아키텍처를 사용해서 더 적은 노력으로 마이크로서비스를 실행,유지,모니터링을 하는 것에 대해서 살펴볼 것이다.

API 구현

API의 설계와 지속적인 개선, 배포, 모니터링 등 API를 관리하는데에는 많은 시간이 들어간다. 때때로 이미 배포된 클라이언트와의 호환성을 보장하기 위해서 여러 버전의 API들을 동시에 실행해야 할 수도 있다. 또한 개발, 테스트, 프러덕션 등의 단계를 가지는 API 배포주기를 관리는 운영비용을 늘린다.

접근 권한 부여는 API에서 가장 중요한 기능이지만, 반복적인 작업이 필요하고 필드하는 것도 복잡하다. API가 성공적으로 배포된 다음의 과제는 API의 관리 모니터링, 그리고 서드파티 개발자들이 쉽게 사용할 수 있도록 해서 생태계를 만드는 것이다.

다른 중요한 과제로는 백앤드 보호, API 응답의 캐싱, Swagger과 같은 도구를 사용해서 API 정의서와 코드, 테스트를 완전히 일치시키는 것이다. Amazon API Gateway는 이러한 문제를 해결하고 RESTFul API를 개발하고 유지하기 위한 복잡성을 줄인다.

API Gateway는 Swagger 정의를 가져와서 프로그래밍을 하는 방식으로 API를 만들 수가 있다. API Gateway는 EC2, ECS, Lambda 등 모든 구축환경의 앞단에서 사용 할 수 있다. 요약하자면 서버 없이도 API를 실행 할 수 있다.

아래 그림은 API Gateway가 API 요청을 읽어서 다른 컴포넌트들을 호출하는 방식을 보여준다.

Distributed Systems Components

AWS를 이용해서 마이크로서비스의 도전과제들을 해결하기 위한 방법들을 살펴봤다. 이제 서비스 디스커버리, 분산 데이터 관리, 데이터 일관성, 비동기 통신 등 분산 시스템을 구성하고 유지하기 위한 여러 방법들을 살펴보도록 하겠다.

서비스 디스커버리

마이크로서비스를 구현하기 위한 중요한 기술적과제로 “서비스가 서로를 발견하기 위한” 서비스 디스커버리가 있다. 마이크로서비스 아키텍처는 분산 시스템에 기반을하고 있기 때문에, 각 서비스간 통신을 어렵게 만든다. 뿐만 아니라 통신하고자 하는 시스템의 상태를 확인하고 애플리케이션이 작동상태가 될 때까지 기다리는 등의 문제를 해결해야 한다. 또한 애플리케이션의 설정정보를 저장하기 위한 meta-store 정보가 어디에 어떻게 저장돼 있는지도 알아야 한다. 여기에서는 마이크로서비스 기반 아키텍처에서 에서 서비스 디스커버리의 수행을 도와주는 AWS의 여러가지 기술에 대해서 살펴볼 것이다.

클라이언트 측 서비스 디스커버리

가장 간단한 접근법은 IP를 이용해서 다른 서비스에 접근하는 것이다. IP는 하드코딩 할 수도있고 설정파일에 넣어 둘 수 있을 것이다. 여기에서 좀 나아가면 /etc/hosts 나 DNS를 구성할 수도 있을 것이다. 이 방법은 동적인 서비스에서는 제대로 작동하지 않을 것이다. 마이크로서비스는 IP와 서비스 포트가 동적으로 바뀌기 때문에 이 방법은 사용 할 수 없다.

Application Load Balancer 기반 서비스 디스커버리

애플리케이션 로드 밸런서는 헬스체크 기능을 가지고 백앤드 서비스를 모니터링 할 수 있다. 만약 서비스가 실패한다면 자동으로 서비스를 등록 취소하며, 서비스가 추가될 경우 자동으로 등록 할 수 있다. 또한 애플리케이션 로드밸런서는 URL Path와 호스트 기반으로 라우팅을 할 수 있다. 여기에 DNS를 결합하면 최소한의 노력과 비용으로 서비스 디스커버리 환경을 만들 수 있다.

DNS 기반 서비스 디스커버리

AWS의 Route 53은 서비스 디스커버리에 활용 할 수 있는 몇 가지 기능을 제공한다. Route 53은 Public 영역(인터넷) 뿐만 아니라 Private 영역(VPC에서 사용 할 수 있는)의 DNS 레코드 셋을 유지 할 수 있다. DNS는 SRV 레코에 IP주소와 Port 주소를 설정 할 수 있는데, 이를 이용해서 마이크로서비스를 디스커버리 할 수 있다. 여기에 Route 53의 Health Check 기능을 이용해서 서비스의 상태를 모니터링 하는 것으로 실패시 서비스에서 제외 시킬 수 있다.

Amazon ECS 이벤트 스트림을 이용한 서비스 디스커버리

AWS ECS는 이벤트 스트림 기능을 제공한다. 이 기능을 이용하면 ECS 클러스터상에서 작동하는 모든 컨테이너 인스턴스의 상태 변화를 실시간으로 노티받을 수 있다. 이 노티는 CloudWatch로 받을 수 있는데, 컨테이너가 시작하거나 종료 이벤트를 받으면 “Route 53의 DNS 엔트리를 수정하는 람다를 실행”하게 할 수 있다.

  • 컨테이너 인스턴스가 실패한다.
  • CloudWatch로 실패 이벤트가 전달된다.
  • 이벤트를 받은 CloudWatch는 Route 53 엔트리를 조작하는 Lambda를 실행한다.
  • 람다는 실패한 엔트리를 삭제한다.

Configuration Management를 이용한 서비스 디스커버리

Chef, Pubbet, Ansible와 같은 외부 설정 관리 툴을 이용해서 서비스 디스커버리를 구현 할 수 있다. EC2 인스턴스가 실행되면, 이들 Agent가 실행이 되면서 설정정보를 등록한다. 이 설정정보들은 인스턴스의 다른 구성정보들고 하마께 중앙 저장소에 기록할 수 있다. 중앙 저장소의 변경내용을 확인해서 이를 서비스 디스커버리 구현에 사용하면 된다.

이 방식의 어려움은 주기적인 헬스체크에 있다. 헬스체크를 하지 못하면 서비스 등록은 쉽게 할 수 있지만 제거는 할 수 없게 된다. 서비스의 상태에 변화가 있을 때, 이를 즉시 알아내서 그에 맞는 행동을 할 수 있어야 한다.

아래 그림은 AWS OpsWorks 설정 관리 시스템으로 서비스 디스커버리를 구현하는 것을 보여주고 있다.

Key Value 스토어를 이용한 서비스 디스커버리

Key Value 스토어로 서비스 디스커버리를 만들 수 있다. 이 방식은 다른 방식보다 구축하는데 많은 시간이 걸리지만 더 유연하고 뛰어난 확장성을 제공하며 DNS 캐싱과 같은 문제도 발생하지 않는다. Netflix Ribbon과 같은 클라이언트 사이드 로드밸랜성 기술과도 연동 할 수 있다. 클라이언트 사이드 분산은 병목현상을 제거하고 관리를 단순화 하는 좋은 솔류션이다.

  1. 새로운 인스턴스가 실행되면, DynamoDB에 상태정보를 업데이트 한다.
  2. DynamoDB 스트림을 이용해서 Table Activity를 캡처 할 수 있다. 이 정보를 Kinesis로 전송 할 수 있다.
  3. Kinsis enabled app을 개발 이 정보를 읽어서 서비스 상태를 업데이트 한다.

분산 데이터 관리

일반적으로 모노리틱 애플리케이션은 모든 애플리케이션 컴포넌트가 공통으로 사용하는 단일 데이터 모델을 정의하고 하나의 거대한 관계형(relational) 데이터베이스에 데이터를 몰아 넣는다. 마이크로서비스는 중앙 데이터베이스 대신 독립된 각 컴포넌트에 별로 데이터를 분산해서 관리한다. 각 마이크로서비스는 고유의 persistence 데이터 레이어를 가지고 있어야 한다.

하지만 분산 데이터베이스는 해결해야 할 다른 과제들이 있다. CAP 이론에 설명된 것처럼, 분산 마이크로서비스 아키텍처는 본질적으로 일관성을 희생하고 성능을 높이면서 궁극적으로는 일관성을 유지할 수 있어야 한다.

AWS는 마스터 데이터를 저장하는 마스터 중앙 저장소를 구축하고, 마이크로 서비스가 중요 데이터를 동기화하고 가능하면 롤백할 수 있는 수단을 제공한다. Amazon Lambda와 CloudWatch를 이용하면 동기화 및 중복 제거 메커니즘을 간단하게 구축 할 수 있다.

데이터의 상태 변경이 마이크로 서비스에 영향을 미치는 것은 일반적인 상황이다. 이러한 경우 이벤트 소싱은 유용한 패턴이다. 이벤트 소싱 패턴의 핵심은 모든 애플리케이션의 변경을 이벤트로 유지하는 것이다. 응용 프로그램은 persistent 상태를 유지하는 대신에 이벤트의 흐름으로 데이터를 갱신한다. 데이터베이스 트랜잭션 로그와 버전 컨트롤 시스템이 이벤트 소싱 패턴을 이용하는 대표적인 기능이다. 이벤트 소싱은 몇 가지 이점이 있다.

  1. 어떤 시점에서든 상태를 결정하고 재구성 할 수 있다.
  2. 자연스럽게 감사를 수행하고 쉽게 디버깅 할 수 있다.
  3. 이벤트 소싱으로 publish/subscribe 패턴을 구현하면 응용 프로그램을 분리 할 수 있으며, 하나의 이벤트를 다양한 마이크로서비스에서 서로 다른 데이터모델로 변환해서 사용 할 수 있다. 이벤트 소싱은 CQRS 패턴(Command, Query, Responsibility, Segregation)과 함께 사용한다. 이 경우 쓰기 작업을 읽기 작업에서 분리해서 성능, 확장성, 보안 능력을 높일 수 있다. 전통적인 데이터베이스 관리 시스템에서 명경과 쿼리는 동일한 데이터 저장소에 대해서 실행된다.

아래 그림은 이벤트 소싱을 이용한 구현을 묘사하고 있다.

API Gatway, EC2, DynamoDB로 구성된 마이크로서비스 1 컴포넌트가 있다. 마이크로서비스 1에 상태변경이 감지되면 Kinesis에 이벤트를 퍼블리싱한다. Kinesis로 전달된 데이터는 S3에 저장해서 향후 Redshift를 이용한 데이터웨어하우징 기반 데이터로 사용한다. 그리고 다시 마이크로서비스 2, 마이크로서비스 3에 전달되서 다른 처리를 수행한다.

비동기 커뮤니케이션과 경량 메시징

전통적인 모놀리틱 애플리케이션의 통신은 비교적 간단하다. 애플리케이션은 메서드 콜이나 내부 이벤트 배포 매커니즘을 이용해서 애플리케이션의 다른 부분과 통신을 한다. 하지만 마이크로서비스의 경우 기존에 하나의 애플리케이션에서 다른 부분이었던 것들이 네트워크 상으로 분리가 될 수 있으며, 자연스럽게 네트워크를 통한 통신이 늘어나게 된다.

REST 기반 커뮤니케이션

HTTP/S 프로토콜은 가장 인기(보편적인)있는 마이크로서비스간 통신 구현체다. 대부분의 경우 ”’RESTful”’ API는 HTTP를 전송계층 프로토콜로 사용한다. REST 아키텍처는 stateless 커뮤니케이션, 통일된 인터페이스, 표준메서드를 골자로한다.

API Gateway를 이용해서 데이터접근과 비지니스 로직을 실행하는 EC2와 Lambda 혹은 컨테이너의 관문(Gateway)을 만들 수 있다. 또한 API Gateway는 각 리소스에 대해서 하나 이상의 메서드, 즉 GET, POST, PUT과 같은 표준 HTTP 메서드에 대해서 응답하도록 구성할 수 있다. 이 API는 개발,스테이징,운영과 같은 여러 단계로 배포 할 수 있도록 스테이지와 버전을 설정 할 수 있다.

API Gateway는 초당 수백에서 수천에 이르는 요청의 수락, 처리를 포함해서 트래픽 관리, 인증, 접근제어, 모니터링 그리고 버전관리 작업을 수행한다.

비동기 메시징

추가적으로 마이크로서비스간의 메시지전달을 위한 message passing 패턴을 사용할 수 있다. 서비스들은 메시지큐(Message queue)를 이용해서 통신한다. 이 통신 방식의 주요 이점은 서비스 검색이 필요하지 않다는 것이다. Amazon Simple Queue Service(SQS)와 Amazon Simple Notification Service(SNS)를 이용해서 message passing 패턴을 구현할 수 있다.

두 서비스는 상호협력적으로 사용 한다. SNS를 이용해서 응용 프로그램에 메시지를 푸시(Push)하는 것으로 여러 구독자에게 메시지를 보낼 수 있다. SNS와 SQS를 이용하면 하나의 메시지를 여러 소비자에게 전달 할 수 있다. 아래 그림은 이 과정을 묘사하고 있다.

Orchestration and State Management

마이크로서비스는 분산 시스템의 특성을 가지며, 이는 서비스와 관련된 전체 흐름의 조율을 어렵게 만들 수 있다. 개발자는 코드에 조율(오케스트레이션) 코드를 직접 넣고 싶은 유혹을 받을 수 있다. 이것은 서비스간 결합도를 높이며, 개별 서비스간 신속한 대처를 어렵게 하기 때문에 피해야 한다.

”’AWS Step Function”’을 이용하면, 분산된 마이크로서비스 애플리케이션을 시각적인 툴을 이용해서 조율 할 수 있다. Step Function은 오류처리와 직렬화/병렬화와 같은 서비스 오케스트레이션의 복잡성을 추상화 하는 상태 시스템을 만들 수 있다. 따라서 서비스 내부에 추가적인 코디네이션 코드를 삽입할 필요 없이 애플리케이션을 빠르게 확장 할 수 있다.

Step Function은 구성 요소들을 조율하고 각 기능을 단계별로 실행할 수 있는 신뢰할 수 있는 솔류션이다. Setop Function은 또한 응용 프로그램의 구성요소를 단계별로 정렬하고 시각화 할 수 있는 그래픽 콘솔을 제공한다.

이러한 툴들을 이용해서 개발자는 분산된 서비스를 쉽게 구축하고 실행 할 수 있다. Step Function은 각 실행 단계를 트리거하고 추척하며, 오류가 생길 대 재 시도하므로 응용 프로그램은 순서대로 실행될 수 있다.

Step Function은 상태 로그를 기록하기 때문에, 문제가 발생하면 신속하게 진단하고 디버깅 할 수 있다. 개발자는 코드의 수정 없이 단계를 추가하고 변경 할 수 있기 때문에 빠르게 프로그램을 개선할 수 있다.

Step Function은 AWS Serverless Platform의 일부이며 EC2와 ECS와 같은 컴퓨터리소스를 기반으로 하는 응용 프로그램뿐만 아니라 람다함수에도 적용 할 수 있다. 아래 그림은 람다와 EC2&ECS가 Step Function을 어떻게 적용하는 지를 보여준다.

워크플로우는 Amazon States Language로 만들 수 있다. 워크플로우는 각 단계에서의 분기 뿐만 아니라, 순차 혹은 병렬 수행까지 기술 할 수 있다. 아래 그림은 분산된 마이크로 서비스를 순차 및 병렬 단계로 결합하는 예재를 보여준다. 이렇게 만들어진 워크플로우는 Step Function 혹은 API Gateway를 통해 수행 할 수 있다.

분산 모니터링

마이크로서비스 아키텍쳐는 컴포넌트들이 서로 분리가 되기 때문에 모니터링하기가 어렵다.

CloudWatch를 이용하면 메트릭을 수집, 추적하며 로그를 중앙에 모아서 모니터링 할 수 있다. 또한 알람을 설정하고 AWS 환경의 변화에 대응 할 수 있다. CloudWatch는 EC2 인스턴스, DynamoDB 테이블, RDS 인스턴스와 같은 AWS 리소스는 물론이고 애플리케이션 및 서비스에서 만들어지는 사용자 정의 매트릭과 로그들을 모니터링 할 수 있다.

모니터링

개발자와 운영자는 CloudWatch를 이용해서 전체 시스템의 리소스 사용율, 애플리케이션의 성능과 운영 상태에 대한 정보를 얻을 수 있다. CloudWatch는 신뢰할 수 있으며 쉽게 확장가능한 모니터링 솔류션을 제공한다. 더 이상 자신의 모니터링 시스템의 구성, 에이전트의 설치, 설정, 관리, 확장에 대해서 걱정 할 필요가 없다. 마이크로 서비스 아키텍처에서는 개발자가 각 서비스에 대해서 수집해야 할 메트릭을 결정할 수 있다.

Centralizing Logs

로그를 남기는 것은 문제를 식별하고 해결하기 위한 중요한 요소다. 마이크로서비스를 통해서 팀은 더 짧은 주기로 자주 제품 릴리즈를 만들 수 있으며 빠르게 새로운 기능을 실험할 수 있다.

대부분의 AWS 서비스는 이미 로그파일을 중앙에 저장하기 위한 장치를 제공하고 있다. AWS의 로그파일은 주로 Amazon S3와 Amazon CloudWatch Log 형태로 저장된다. EC2 인스턴스위에서 실행되는 인스턴스들도 데몬 프로그램을 사용해서 CloudWatch로 전송 할 수 있다. 람다는 로그를 CloudWatch로 전달하며, ECS는 awslogs 로그드라이버를 이용해서 CloudWatch로 보낼 수 있다.

아래 그림은 서비스 로깅 기능을 보여준다. 팀은 Amazon Elasticsearch와 Kibana와 같은 도구를 이용해서 로그를 분석 할 수 있다. S3에 저장된 로그는 Athena를 이용해서 임의 쿼리를 실행 할 수도 있다.

분산추적

마이크로서비스 아키텍처에서는 하나의 요청에 대해서 여러 개의 마이크로서비스가 작동을 처리한다. 이러한 처리 흐름에서 서비스 중 하나에서 에러가 발생할 경우를 생각해보자. 비록 각 마이크로서비스가 로깅되고 있다고 하더라도 관련 로그를 분석하면서 에러 원인을 찾는 것은 매우 어려울 수 있다.

Amazon X-RAY는 각 마이크로서비스의 요청 흐름에 고유한 ID를 부여하고, 이 ID를 이용해서 요청을 추적할 수 있게 한다. 요청이 API Gateway 혹은 Application Load Balancer로 들어오면 X-Amzn-Tracd-Id 라는 헤더에 요청추적을 위한 ID를 추가한다. 애플리케이션은 X-Ray SDK를 이용해서 이 헤더를 추가하거나 업데이트 할 수 있다.

AWS X-Ray는 EC2, ECS, Lambda, Elastic Beanstalk에서 작동하며, Java, Node.js, .NET, Go 언어를 위한 X-Ray SDK를 제공한다.

로그 분석을 위한 옵션

로그 데이터를 검색, 분석하고 시각화는 분산 시스템의 이해를 위한 중요한 요소다. 로그 파일을 분석하는데 사용하는 옵션 중 하나는 Amazon ES와 Kibana를 함께 사용하는 것이다.

Amazon ES(ElasticSearch)는 풀 텍스트 검색을 이용해서 구조화된 검색, 분석을 위해서 사용한다. Kibana는 Amazon ES와 함께 사용 할 수 있는 오픈소스 데이터 시각화 플러그인이다. Amazon ES의 쿼리와 연동해서 그 결과를 시각화 한다.

아래 그림은 Amazon ES와 Kibana를 이용한 로그분석 과정을 보여준다. ClodWatch Logs는 CloudWatch Logs subscription을 통해서 거의 실시간으로 Amazon ES의 데이터 저장소에 색인된다. Kibana는 ES에 저장된 데이터를 시각화 하기 위한 편리한 검색 인터페이스를 제공한다. 이 솔루션은 ElastAlert와 같은 소프트웨어와 함께 사용 해서 데이터 예외나 관심패턴이 감지되면 SNS, Email, Jira 로 전송하는 경고 시스템을 구현 할 수 있다.

Amazon Redshift와 Amazon QuickSight를 이용한 로그 분석 방법도 있다. Amozon Redshift는 페타바이트 규모의 데이터를 적은 비용으로 빠르게 분석 할 수 있는 완전관리형 데이터웨어 하우스 서비스다. QuickSight는 ad-hoc한 분석을 수행하고 그 결과를 시각화 하기 위한 서비스다. QuickSight는 Redshift, RDS, Aurora, EMR, DynamoDB, S3, Kinesis 등과 쉽게 연결 할 수 있다.

Amazon CloudWatch Logs를 이용하면 로그데이터를 중앙에 모을 수 있다. 또한 Kinesis Firehose를 이용해서 로그 스트림을 저장소로 보낼 수도 있다. 아래 그림은 CloudWatch와 Kinesis Firehose를 이용해서 다양한 로그들을 Redshift로 스트리밍하고, QuickSight를 이용해서 시각화 하는 과정을 보여준다.

아래 그림은 S3에 있는 데이터를 분석하는 과정을 보여주고 있다. S3에 저장된 로그는 EMR이나 Redshift에 올려서 분석할 수 있다.

Auditing

마이크로서비스 아키텍처가 해결해야 할 과제들은 “분산 시스템”이기 때문인 경우가 많다. 서비스의 보안,모니터링 정책을 수행하려면 시스템에서 이루어지는 활동들을 감사할 수 있어야 한다. 마이크로서비스는 다양한 영역에서 변화가 발생하기 때문에 감사가 중요하다.

Audit Trail

AWS CloudTrail은 AWS Cloud에서 발생하는 모든 API 호출들을 CloudWatch Logs에 기록하거나 S3로 보낼 수 있기 때문에, 마이크로 서비스의 변경을 추적하는데 유용하게 사용 할 수 있다.

모든 사용자의 작업과 자동화된 작업을 검색할 수 있어서 예기치 않은 동작, 정책 위반을 분석하거나 디버깅 할 수 있다. 이 정보는 사용자/계정 정보, 시간, 요청 작업과 호출한 서비스, 호출자의 IP 주소, 요청 매개변수와 응답들이 포함된다.

CloudTrail은 권한과 목적(개발자인지 감사자인지 등)에 따라서 자신만의 트레일을 만들어서 관리 할 수 있다. 이는 마이크로서비스 팀마다 역할 특성에 맞는 트레일을 집계할 수 있게 한다.

CloudTrail로그를 S3 버킷에 파일형태로 저장하는 것은 몇 가지 장점을 가진다. 트레일 데이터를 영구적으로 저장할 수 있다. 새로운 파일이 만들어지면 SNS 알림을 보내거나 Lambda 함수를 실행해서 로그 파일을 파싱 하고, 로그주기 정책에 따라서 Amazon Glacier에 자동으로 아카이빙 할 수 있다. 또한 EMR , Redshift와 같은 서비스를 활용해서 데이터를 분석 할 수 있다.

CloudWatch를 이용하면 실시간으로 트레일 데이터를 읽을 수 있으며, Amazon ES로 라우팅해서 빠르게 분석결과를 얻을 수 있다. 물론 S3와 CloudWatch 양쪽 모두에 로그를 남기도록 CloudTrail를 구성할 수도 있다.

Events and Real-time Actions

인터넷 서비스 아키텍처는 변화가 있을 때 관리정책에 따라서 신속하게 대응 할 수 있어야 한다. CloudWatch 이벤트는 CloudTrail과 통합할 수 있으며, 거의 실시간으로 시스템 이벤트를 받아볼 수 있다. 관리자는 규칙에 따라서 자동화된 처리 시스템을 만들 수도 있다.

이벤트는 시스템에서 정의한 규칙에 따라서 조직의 적합한 사람에게 즉시 통보할 수 있다. 이를 통하여서 사용자는 적절한 조치를 취할 수 있게된다. 더 나아가서 내장된 워크플로우를 트리거하거나 람다펑션을 호출 할 수도 있다.

아래 그림은 마이서비스 아키텍처에서 감사 와 수정요구사항의 처리를 위해서 CloudTrail과 CloudWatch가 협업해서 작동하는 모습을 보여준다. 모든 마이크로 서비스는 CloudTrail에 의해 추적되며 그 결과는 S3에 저장된다. CloudWatch는 CloudTrail에 변화가 감지 될때 경고 이벤트를 트리거한다.

Resource Inventory and Change Management

마이크로서비스를 관리하는 애자일팀은 빠르게 변하는 인프라를 관리하기 위해서 자동화된 방법을 사용할 필요가 있다.

CloudTrail과 CloudWatch 이벤트를 이용해서 마이크로서비스 인프라의 변경사항을 추적할 수 있다. AWS Config를 이용하면 보안정책을 정의 해서 정책위반사항을 자동으로 탐지및 추적,경고 할 수 있다.

아래 예제에서 개발자팀은 마이크로서비스를 위한 API Gateway의 서비스 포트로 HTTP(80)를 오픈했다. API Gateway는 HTTPS(443)만을 오픈해야 하기 때문에 보안정책위반이다. AWS Config는 이러한 유형의 위반사항을 읽어서 보안위반이라는 것을 식별하고 두 가지 작업을 수행한다.

  1. 감지된 변경 로그를 S3에 저장한다.
  2. SNS 알림을 생성한다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

Bitnami