Strategy 2 – Split Frontend and Backend
(두번째 전략 - Frontend와 Backend의 분리)

Monilithic Application을 축소시키는 전략은 비즈니스 로직과 데이터 액세스 레이어에서 프리젠테이션 레이어를 분리하는 것이다.

일반적으로 엔터프라이즈 어플리케이션은 최소한 3가지 다른 유형의 컴포넌트들로 이루어져 있다.

프리젠테이션 레이어 - HTTP 요청을 처리하고, (REST) API나 HTML 기반 Web UI를 구현하는 구성 요소. 정교한 사용자 인터페이스를 가지고 있는 어플리케이션에서 프리젠테이션 계층은 종종 상당한 코드로 구성되어 있다.
비즈니스 레이어 - 어플리케이션의 핵심 영역이며, 비즈니스 규칙을 구현하는 구성 요소.
데이터 액세스 레이어 - 데이터베이스나 메시지 브로커와 같은 인프라 구성 요소들에 액세스하는 구성 요소

일반적으로 프리젠테이션 로직 영역과 비즈니스, 데이터 액세스 로직 사이는 분명하게 분리되어 있다. 비즈니스 계층은 비즈니스 로직 컴포넌트들을 캡슐화하는 하나 이상의 facade(진입점 역할을 하는 인터페이스)로 이루어진 대단위 API를 가지고 있다. 이 API는 monolith를 2개의 더 작은 어플리케이션으로 나눌 수 있는 자연적인 솔기이다. 한 개의 어플리케이션은 프리젠테이션 레이어를 가지고 있다. 다른 어플리케이션은 비즈니스와 데이터 액세스 로직이 포함되어 있다. 이렇게 분리한 후, 프리젠테이션 로직 어플리케이션은 비즈니스 로직 어플리케이션을 원격으로 호출하게 된다. 다음 다이어그램은 리팩토링 전후의 아키텍처를 보여주고 있다.

사용자 삽입 이미지



이 방법으로 monolith를 분할하는 것은 2가지 주요 장점이 있다. 서로간에 독립적으로 2개의 어플리케이션을 개발, 배포, 확장할 수 있다. 특히, 프리젠테이션 레이어 개발자는 사용자 인터페이스를 빠르게 반복하여 개발할 수 있다. 그리고 예를 들면, 쉽게 A|B 테스트를 수행할 수 있다. 이 접근방법의 또다른 장점은 개발한 마이크로서비스에서 호출할 수 있는 원격 API를 제공한다는 것이다.

그러나, 이 전략은 단지 부분적인 해결책일 뿐이다. 한 두개의 관리할 수 없는 monolith 어플리케이션에 대한 해결책일 공산이 크다. 나머지 monolith를 제거하기 위해서는 3번째 전략을 사용하는 것이 필요하다.
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/783


이번 기사는 Microservice로 Application을 작성하는데 있어서 7번째이자, 마지막 글이다. 첫번째 글에서는 Microservice Architecture 패턴에 대해서 소개하고, Microservice를 사용하는 장단점에 대해서 논의했다. 다음 글에서는 API Gateway 사용, Inter-process communication, 서비스 검색, Event-Driven 데이터 관리, Microservice 배포 등의 다양한 측면에 대해서 논의했다. 이번 글에서는 monolithic application을 microservice로 마이그레이션(전환)하는 전략에 대해서 살펴 보려고 한다.

이 시리즈 기사들을 통해서 microservice architecture와 장단점, 언제 사용하는지에 대해 이해할 수 있도록 돕고자 한다. Microservice Architecture가 여러분의 조직에 적합할 수도 있다.

그러나, 크고 복잡한 monolithic application을 작성하는 정말 좋은 기회가 있다. Application 개발과 배포에 대한 일상적인 경험은 느리고 고통스럽다. Microservice는 머나먼 너바나(열반, 해탈)처럼 보인다. 다행스럽게도 Monolithic Hell에서 벗어나는데 사용할 수 있는 전략이 있다. 이 기사에서는, Monolithic Application을 Microservice로 점진적으로 리팩토링하는 방법에 대해서 설명할 것이다.

Overview of Refactoring to Microservices
(Microservice로 리팩토링하기 개요)

Monolithic Application을 Microservice로 변환하는 과정은 Application 현대화의 한 형태이다. 개발자들이 수십년동안 해왔던 일이기도 하다. 결과적으로, Application이 Microservice로 리팩토링할 때, 재사용할 수 있는 몇 가지 아이디어들이 있다.

사용하지 않는 전략 중 한가지는 "Big Bang" 재개발이다. Big Bang은 아무런 사전 준비 없이 새로운 Microservice 기반 Application을 개발하는데 모든 역량을 집중해야 한다. 호소력 있는 것처럼 들리지만, 극도로 위험하고 실패로 끝나기 쉽다. Martin Fowler가 리포트에서 말하는 것처럼, "Big Bang 재개발을 보장하는 유일한 방법은 Big Bang 뿐이다."

Big Bang 재개발 대신에, Monolithic Application을 점진적으로 리팩토링해야 한다. 점차적으로 Microservice를 구성하는 신규 Application을 개발하여 monolithic application과 함께 실행한다. 시간이 지나면, monolithic application으로 구현된 기능의 양은 완전히 사라지거나 또다른 microservice가 될 때까지 줄어든다. 이 전략은 고속도로에서 시속 70마일로 운전하는 도중에 자동차 정비하는 것과 유사한 도전이지만, Big Bang 재개발보다 훨씬 덜 위험하다.

Martin Fowler는 이러한 Application 현대화 전략을 Strangler Application(교착 상태 응용 프로그램)이라고 한다. 그 이름은 열대 우림에서 발견되는 strangler vine (a.k.a strangler fig - 알려진 것처럼, 다른 나무에 기생하여 그 나무를 감고 올라가 말려 죽이는 나무의 한 종류. 직역하면, 교살 포도 나무)에서 비롯되었다. 가끔은 나무가 죽어서 포도 나무 모양을 남긴다. Application 현대화도 같은 패턴을 따른다. Legacy Application 주위에  Microservice로 구성된 새로운 Application을 구축하고, 결국 Legacy Application은 사라질 것이다.

사용자 삽입 이미지


이제, 다른 전략을 살펴보자.

Strategy 1 – Stop Digging
(첫번째 전략 - 채굴 금지)

홀의 법칙(Law of Hole)은 구멍에 있을 때마다 채굴하는 것을 멈춰야 한다는 것을 알려주고 있다. 이것은 monolithic application을 관리할 수 없을 때, 따라야할 훌륭한 조언이다. 다른 말로 하면, monolithic application을 더 크게 만드는 것을 멈춰야만 한다. 이것은 신규 기능을 구현할 때, monolithic에 코드를 추가하지 않아야 한다는 것을 의미한다. 대신에 이 전략의 커다란 아이디어는 독립형 microservice에 새로운 코드를 넣는 것이다. 다음 다이어그램은 이러한 접근법을 적용한 시스템 아키텍처를 보여준다.

사용자 삽입 이미지


새로운 서비스와 legacy monolith 뿐만 아니라, 2가지 구성 요소들이 있다. 첫번째는 HTTP 요청을 처리하는 Request Router이다. 앞서 기사에서 설명한 API Gateway와 유사하다. Router는 새로운 기능에 대한 요청을 새로운 서비스로 보낸다. Legacy 요청은 monolith로 전송한다.

다른 구성 요소는 Glue Code이다. "Glue Code"는 Monolith에 통합되어 있다. 서비스는 격리되어 있지 않고, 종종 Monolith에서 보유하고 있는 데이터에 접근해야 한다. Monolith나 서비스 혹은 양쪽 모두에 있는 "Glue Code"가 데이터 통합을 담당한다. 서비스는 Monolith에 있는 데이터를 읽거나 쓰는데 Glue Code를 사용한다.

서비스가 monolith 데이터에 접근하는데 3가지 전략이 있다.

1. Monolith에서 제공하는 원격 API 호출
2. Monolith의 데이터베이스에 직접 접근
3. Monolith의 데이터베이스와 동기화된 자체 복사본 데이터 유지

Glue Code는 때때로 Anti-corruption Layer(반부패 계층)로 불리기도 한다. 왜냐하면 본래의 도메인 모델을 가진 서비스가 Legacy Monolith 도메인 모델이 갖는 개념에 의해 오염되는 것을 Glue Code가 방지하기 때문이다. Glue Code는 2가지 다른 모델들 사이에 변환된다. Anti-corruption Layer라는 용어는 읽어야만 하는 책, 이후 백서로 개량된 Eric Evans의 Domain Driven Design에서 처음 나타났다. Anti-corruption Layer를 개발하는 것은 사소한 일이 될 수도 있다. 그러나, monolithic hell에서 벗어나기 원한다면, 하나를 창조하는 것이 필수적이다.

가벼운 서비스로써 새로운 기능을 구현하는 것은 몇 가지 장점이 있다. Monolith가 더 관리할 수 없게 되는 것을 방지한다. 서비스를 monolith와 독립적으로 개발, 배포, 확장할 수 있다. 신규로 만드는 서비스마다 Micorservice Architecture의 장점을 경험할 수 있다.

그러나, 이러한 접근 방법이 monolith의 모든 문제점을 해결하는 것은 아니다. 이러한 문제들을 해결하려면 monolith를 분해할 필요가 있다. 그렇게 하기 위한 전략을 살펴 보자.

받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/782

Summary
(요약)

Microservice Application을 배포하는 것은 어렵다. 다양한 언어와 프레임워크로 개발된 수십, 수백개의 서비스들이 있다. 각각은 고유의 특정 배포, 리소스, 확장, 모니터링 요구사항들을 가지고 있는 mini-application이다. Service Instance per Virtual Machine과 Service Instance per Container를 포함하여 여러 가지 Microservice 배포 패턴들이 있다. Microservice 배포에 대한 또 다른 흥미로운 옵션에는 서버가 없는 접근방식인 AWS Lambda가 있다. 이 시리즈의 마지막인 다음에서는 Monolithic Application을 Microservice Architecture로 전환하는 방법에 대해서 살펴볼 것이다.
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/781

Serverless Deployment
(서버 없는 배포)


AWS Lambda는 서버없는 배포 기술의 한 예이다. AWS Lambda는 Java, Node.js, Python 서비스를 지원한다. Microservice를 배포하기 위해서는, ZIP 파일로 패키지하고, AWS Lambda로 업로드하면 된다. 또한, AWS Lambda를 통해서 다른 여러 사항들 중에서 요청을 처리하기 위해 호출되는 함수 이름을 지정하는 메타데이터를 제공할 수도 있다. (a.k.a. an event : also known as - 이벤트라고도 알려진) AWS Lambda는 요청을 처리하기 위해 충분한 Microservice 인스턴스를 자동으로 실행한다. 소요된 시간과 메모리 사용량에 근거하여 각 요청에 대해 간단히 과금하게 된다. 물론, 악마는 세부 사항 내에 있으며, AWS Lambda에 제한 사항이 있음을 알게 될 것이다. 그러나, 개발자나 조직 내 다른 누군가가 서버나 Virtual Machine, 컨테이너 등의 어떤 측면에 대해서도 걱정할 필요가 없다는 개념은 믿을 수 없을 정도로 매력적이다.

Lambda 함수는 상태를 저장하지 않는 서비스이다. 일반적으로 AWS 서비스를 호출하여 요청을 처리한다. 예를 들면, S3 Bucket에 이미지를 업로드하는 경우에 호출되는 Lambda 함수는 항목을 DynamoDB 이미지 테이블에 삽입하고, 이미지 처리를 트리거링하기 위하여 Kinesis 스트림에 메시지를 게시한다. Lambda 함수는 third-party 웹 서비스도 호출할 수 있다.

Lambda 함수를 호출하기 위하여 4가지 방법이 있다. :

1. 웹 서비스 요청을 사용하여 직접적으로 호출
2. S3, DynamoDB, Kinesis, Simple Email Service와 같은 AWS 서비스에서 생성된 이벤트에 대한 응답으로 자동으로 호출
3. Application Client로부터 HTTP 요청을 다루기 위하여 AWS API Gateway를 통해 자동으로 호출
4. Cron과 같은 스케쥴에 따라 주기적으로 호출

보는 것과 같이, AWS Lambda는 Microservice를 배포하는데 편리한 방법이다. 요청 기반 가격 정책은 서비스가 실제로 수행하는 작업에 대해서만 과금한다는 뜻이다. 또한, IT 인프라에 대한 책임을 지지 않아도 되기 때문에 Application 개발에만 집중할 수 있다.

그러나, 몇 가지 중요한 제한 사항들이 있다. Third-party 메시지 브로커로부터 메시지를 사용하는 서비스와 같이, 장시간 실행되는 서비스를 배포하는데 사용하려는 것이 아니다. 요청 사항들은 300 초 내에 완료되어야 한다. 이론적으로는 AWS Lambda가 각 요청에 대해 별도의 인스턴스를 실행할 수 있기 때문에 서비스들은 상태를 저장하지 않아야 한다. 또한 서비스들은 지원되는 언어들 중에 하나로 구현되어야 한다. 서비스들은 빠르게 시작되어야 한다. 그렇지 않으면, 타임 아웃으로 종료될 수 있다.
받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/780


Service Instance per Host Pattern
(호스트별 단일 서비스 인스턴스 패턴)

Microservice를 배포하는 또 다른 방법은 호스트 별로 하나의 서비스 인스턴스를 배포하는 패턴이다. 이 패턴을 사용할 때, 각 서비스 인스턴스는 자체 호스트에서 독립적으로 실행된다. 이 패턴에는 VM(Virtual Machine)별 서비스 인스턴스 배포 패턴과 컨테이너별 서비스 인스턴스 배포 패턴의 2가지 다른 특별한 유형이 있다.

Service Instance per Virtual Machine Pattern
(Virtual Machine별 서비스 인스턴스 패턴)

VM별 서비스 인스턴스 배포 패턴을 사용하면, 각 서비스를 아마존 EC2 AMI처럼 VM 이미지로 패키징한다. 가거 서비스 인스턴스는 VM 이미지를 사용하여 실행되는 VM(예를 들면, EC2 인스턴스)이다. 다음 다이어그램은 이 패턴의 구조를 보여준다.

사용자 삽입 이미지


이것은 Netflix에서 비디오 스트리밍 서비스를 배포하기 위해 사용했던 기본 접근 방법이다. Netflix는 Aminator를 사용한 EC2 AMI로 각 서비스를 패키징한다. 실행되는 각 서비스 인스턴스는 EC2 인스턴스이다.

자체 VM을 구축하는데 사용할 수 있는 다양한 툴이 있다. EC2 AMI로 서비스를 패키징하기 위해 Aminator를 호출하여 Continuous Integration (CI, 예 : Jenkins) 서버를 구성할 수 있다. Packer.io는 자동으로 VM 이미지를 생성하기 위한 또다른 옵션이다. Aminator와는 다르게, Packer.io는 EC2, DigitalOcean, ViurualBox, VMWare를 포함하여 다양한 가상화 기술을 지원한다.

Boxfuse 회사는 위에서 언급한 VM들의 단점을 극복한 강력한 VM 이미지 구축 방법을 가지고 있다. Boxfuse는 Java Application을 최소한의 VM 이미지로 패키징한다. 이러한 이미지들은 빌드가 빠르고, 부팅도 빠르고, 제한된 공격 영역을 노출하기 때문에 더 안전하다.

CloudNative는 EC2 AMI 생성을 위한 SaaS 제공 업체인 Bakery를 보유하고 있다. Microservice 테스트 단계 패스 이후 Bakery를 호출하도록 CI 서버를 구성할 수 있다. Bakery는 서비스를 AMI로 패키징한다. Bakery와 같은 SaaS 제공 업체를 사용하는 것은 AMI 생성 인프라 구성에 귀중한 시간을 낭비할 필요가 없다는 것을 의미한다.

VM별 단일 서비스 인스턴스 배포 패턴은 많은 장점이 있다. VM의 주요 이점은 각 서비스 인스턴스가 완벽히 독립되어 실행된다는 것이다. 고정된 CPU와 메모리 용량을 가지고, 다른 서비스의 리소스를 도용할 수 없다.

Microservice를 VM으로 배포하는 또다른 장점은 성숙한 클라우드 인프라를 활용할 수 있다는 것이다. AWS와 같은 클라우드는 로드 밸런싱(부하 분산)이나 Auto-Scaling(자동 확장)과 같은 유용한 기능을 제공한다.

또다른 큰 장점은 서비스 구현 기술을 캡슐화 한다는 것이다. 일단 VM으로 서비스가 패키징되면, Black Box(블랙 박스)가 된다. VM을 관리하는 API는 서비스를 배포하는 API가 된다.(VM 관리 API로 서비스를 배포할 수 있다.) 훨씬 간단하고 안정적으로 배포하게 된다.

그러나, Service Instance per Virtual Machine (VM별 서비스 인스턴스 배포) 패턴은 몇 가지 단점이 있다. 한가지 단점은 리소스 사용 관점에서는 덜 효율적이다. 각 서비스 인스턴스는 OS를 포함하여 전체 VM 오버헤드가 있다. 더우기, 일반적인 공용 IaaS에서는 VM은 고정된 크기를 가지고 있으며, VM을 충분히 활용하지 못할 수도 있다.

다른 관점에서 보면, 일반적으로 공용 IaaS는 VM의 사용 여부와 무관하게 과금한다. AWS와 같은 IaaS는 Auto-Scaling을 지원하지만, 수요 변화에 빠르게 반응하는 것은 어렵다. 결과적으로, VM을 과도하게 준비해야 하므로 배포 비용이 증가하게 된다.

이 접근 방법의 또 다른 단점은 새로운 버전의 서비스를 배포하는 것이 일반적으로 느리다는 것이다. VM 이미지는 크기 때문에 빌드 속도가 느리다. 또한, 크기 때문에 VM은 인스턴스화 하는 것도 느리다. 그리고 OS는 시작하는데 약간 시간이 걸린다. 그러나, Boxfuse로 빌드된 경량화된 VM들이 존재하기 때문에 보편적이라고 말하기는 어렵다.

Service Instance per Virtual Machine 패턴의 또다른 단점은 일반적으로 여러분(혹은 조직의 다른 사람)이 많은 구분되지 않은 들어올리기 힘든 일을 감당한다는 것이다. VM을 빌드하고, 관리하는 오버헤드를 처리하기 위해 Boxfuse와 같은 툴을 사용하지 않는다면, 모두 여러분의 책임이다. 이렇게 필수적이지만 시간을 소모하는 활동은 핵심 비즈니스에서 (여러분의 관심사를) 다른 곳으로 돌린다.

자, 이제 더 가볍고 VM의 많은 이점을 갖는 Microservice 배포에 대한 대안을 살펴보자.

Service Instance per Container Pattern
(컨테이너별 서비스 인스턴스 패턴)

Service Instance per Container (컨테이너별 서비스 인스턴스) 패턴을 사용하는 경우, 각 서비스 인스턴스는 자체 컨테이너에서 동작한다. 컨테이너는 OS 수준 가상화 메커니즘이다. 컨테이너는 샌드박스 내에서 실행되는 하나 이상의 프로세스로 이루어져 있다. 프로세스 관점에서, 프로세스는 자체 포트 네임스페이스와 루트 파일 시스템을 가지고 있다. 컨테이너별로 메모리와 CPU 리소스를 제한할 수 있다. 어떤 컨테이너 구현체에는 I/O 비율 제한도 있다. 컨테이너 기술의 예로 Docker와 Solaris Zones가 있다.

다음 다이어그램에서는 이 패턴의 구조를 보여준다.

사용자 삽입 이미지


이 패턴을 사용하기 위해서는 서비스를 컨테이너 이미지로 패키지해야 한다. 컨테이너 이미지는 Application과 서비스 실행에 필요한 라이브러리들로 구성된 파일 시스템 이미지이다. 일부 컨테이너 이미지는 완전한 리눅스 루트 파일 시스템으로 이루어져 있다. 다른 것들은 더 가볍다. 예를 들면, Java 서비스를 배포하기 위해서 Java Runtime(아마도 Apache Tomcat 서버)과 컴파일된 Java Application을 포함하여 컨테이너 이미지를 빌드 한다.

일단, 서비스를 컨테이너 이미지로 패키징하면 하나 이상의 컨테이너를 실행한다. 각 실제 서버 혹은 가상 서버에서 일반적으로 여러 개의 컨테이너를 실행한다. 컨테이너들을 관리하기 위해서 Kubernetes나 Marathon과 같은 클러스터 관리자를 사용할 수도 있다. 클러스터 관리자는 호스트를 리소스 풀(pool)로 다룬다. 컨테이너가 필요로하는 리소스와 각 호스트에서 이용가능한 리소스를 기반으로 각 컨테이너를 어디에 배치할 지를 결정한다.

Service Instance per Container(컨테이너별 서비스 인스턴스) 패턴은 장단점이 모두 있다. 컨테이너의 장점은 VM과 유사하다. 서비스 인스턴스가 서로 격리되어 있다. 각 컨테이너가 사용하는 리소스를 쉽게 모니터링 할 수 있다. 또한 VM처럼, 컨테이너는 구현된 서비스를 캡슐화한다. 서비스를 관리하기 위한 API로 컨테이너 관리  API를 제공한다.

그러나 VM과는 다르게, 컨테이너는 가벼운 기술이다. 컨테이너 이미지는 일반적으로 매우 빠르게 빌드된다. 예를 들면, 랩톱에서 Spring Boot Application을 Docker 컨테이너로 패키징하는데 약 5초가 걸린다. 지루한 OS 부팅 메커니즘이 없기 때문에 컨테이너는 매우 빠르게 시작된다. 컨테이너가 시작될 때, 서비스도 시작된다.

컨테이너를 사용하는 것에는 몇 가지 단점이 있다. 컨테이너 인프라스트럭처가 급속도로 성숙하고 있으나, VM만큼 성숙하지는 못했다. 또한, 컨테이너들은 호스트 서버 OS의 커널을 서로 공유하므로 VM만큼 안전하지 못하다.

컨테이너의 또다른 단점은 컨테이너 이미지를 관리하는데 구분되지 않은 들어올리기 힘든 책임이 있다는 것이다. 또한 Google Container Engine이나 Amazon EC2 Container Service(ECS)와 같은 호스팅되는 컨테이너 솔루션을 이용하지 않는다면, 컨테이너 인프라와 실행되는 VM 인프라를 관리해야만 한다.

그리고, 컨테이너는 종종 VM 단위 과금되는 인프라에 배포된다. 결과적으로, 앞에서 언급한 것처럼, 급증한 부하를 처리하기 위하여 과도하게 VM을 준비하여 초과 비용을 초래할 수도 있다.

흥미롭게도, 컨테이너와 VM 사이의 차이점이 모호해질 수도 있다. 앞에서 언급한 것처럼, Boxfuse VM은 빠르게 빌드하고 빠르게 시작할 수 있다. Clear Container 프로젝트의 목표는 가벼운 VM을 생성하는 것이다. unikernel에 대한 관심도 증가하고 있다. Docker, Inc는 최근에 Unikernel Systems를 인수했다.

또한 Server-less 배포에 대한 새롭고 인기가 증가하고 있는 개념도 있다. 이 개념은 서비스를 배포하기 위해 컨테이너나 VM 중에 선택하는 이슈를 회피하는 접근 방법이다. 다음에서 살펴보자

받은 트랙백이 없고, 댓글이 없습니다.

댓글+트랙백 RSS :: http://www.yongbi.net/rss/response/779