Choosing a Microservices Deployment Strategy
(Microservice 배포 전략 선택)

이것은 Microservice로 Application을 작성하는 시리즈 중에서 여섯번째 글이다. 첫번째 글에서는 Microservice Architecture Pattern을 소개하고, Microservice 사용에 대한 장단점을 논의했다. 그 다음 글에서는 Microservice Architecture의 다양한 측면 : API Gateway 사용, 프로세스간 통신, 서비스 검색, Event-Driven 데이터 관리 등에 대해서 살펴보았다. 이번 글에서는 Microservice 배포 전략에 대해서 살펴보자.

Motivations
(동기)

Monolithic Application을 배포하는 것은 일반적으로 하나의 대용량 Application을 여러 개의 동일한 복사본으로 실행한다는 것을 의미한다. 일반적으로 N개의 서버(실제 혹은 가상)를 준비하고, 각 서버마다 M개의 Application 인스턴스를 실행한다. Monolithic Application 배포는 항상 전적으로 쉽지는 않지만, Microservice Application을 배포하는 것보다는 훨씬 간단하다.

Microservice Application은 수십 혹은 수백개의 서비스로 이루어진다. 서비스는 다양한 언어와 프레임워크로 작성된다. 각각의 서비스는 그 자체적인 배포, 리소스, 확장, 모니터링 요구사항을 가진 작은 응용프로그램(mini-application)이다. 예를 들어, 각 서비스에 대한 수요 기반으로 특정 개수의 서비스 인스턴스를 실행할 필요가 있다. 각 서비스 인스턴스는 적당한 CPU, Memory, I/O 리소스를 제공받아야 한다. 더 까다로운 것은 이러한 복잡성에도 불구하고, 서비스들의 배포는 빠르고, 안정적이고, 비용 효율적이어야 한다는 것이다.

몇 가지 다른 Microservice 배포 패턴이 있다. 먼저, Host별 다중 서비스 인스턴스 패턴(Multiple Service Instance per Host pattern)에 대해서 살펴보자.

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

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


Summary
(요약)

Microservice Architecture에서는 각 마이크로서비스가 자체적으로 데이터 저장소를 가지고 있다. 다른 Microservice들은 서로 다른 SQL 및 NoSQL 데이터베이스를 사용할 수 있다. 이러한 데이터베이스 아키텍처는 상당한 장점이 있지만, 분산 데이터를 다루는데 있어서 관리 문제가 발생한다. 첫번째 과제는 여러 서비스들 간에 데이터 일관성을 유지하는 비즈니스 트랜잭션을 어덯게 구현하느냐는 것이다. 두번째 과제는 여러 서비스에서 데이터를 검색하는 쿼리를 어떻게 구현하는가이다.

많은 Application에서 해결책은 Event-Driven Architecture를 사용하는 것이다. Event-Driven Architecture를 구현하는데 있어서 한 가지 문제는 상태를 원자적으로 업데이트하고 이벤트를 게시하는 것이다. 데이터베이스를 메시지 큐로 이용하는 방법, 트랜잭션 로그 마이닝으로 이용하는 방법, 이벤트 소싱으로 이용하는 방법등을 포함하여 몇 가지 방법이 있다.

앞으로의 블로그 글에서는 Microservice의 다른 측면에 대해서도 깊이 들여다 볼 것이다.
받은 트랙백이 없고, 댓글이 없습니다.

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


Achieving Atomicity
(원자성 달성)

Event-Driven Architecture에서는 데이터베이스를 원자적으로 업데이트하고 이벤트를 게시하는 문제가 있다. 예를 들면, Order Service는 ORDER 테이블에 행을 입력하고, Order Created Event를 게시해야 한다. 이 두가지 작업들은 원자적으로 수행되는 것이 필수적이다. 만약에 데이터베이스를 업데이트하고 이벤트를 게시하기 전에 서비스가 충돌하면 시스템은 데이터 일관성을 잃게 된다. 원자성을 보장하는 표준적인 방법은 데이터베이스와 Message Broker가 분산 트랜잭션을 사용하는 것이다.
그러나, 위에서 언급된 CAP이론과 같은 이유들 때문에 이것은 우리가 정확히 원하지 않는 것이다.

Publishing Events Using Local Transactions
(로컬 트랜잭션을 사용한 이벤트 게시)

원자성을 달성하는 한가지 방법은 Application이 로컬 트랜잭션만을 포함하는 Multi-step process를 사용하여 이벤트를 게시하는 것이다. 트릭은 Business Entity의 상태를 저장하는 데이터베이스에 Message Queue로서의 기능을 갖는 EVENT 테이블을 가지는 것이다. Application은 (로컬) 데이터베이스 트랜잭션을 시작하고, Business Entity의 상태를 업데이트한다. 그리고 이벤트를 EVENT 테이블에 입력하고, 트랜잭션을 커밋한다. 별도로 분리된 Application이나 Process가 EVENT 테이블에 질의하여 Message Broker에 이벤트를 게시하고, 이벤트가 게시되었음을 표시하기 위해 로컬 트랜잭션을 사용한다. 다음 다이어그램은 디자인을 보여 준다.

사용자 삽입 이미지


Order Service는 ORDER 테이블에 행을 삽입하고, EVENT 테이블에 Order Created 이벤트를 삽입한다. Event Publisher Thread나 Process는 게시되지 않은 이벤트에 대해 EVENT 테이블에 질의하고, 이벤트를 게시하고 나서 이벤트가 게시되었음을 표시하기 위해 EVENT 테이블을 업데이트한다.

이러한 접근 방법은 몇 가지 장점과 단점이 있다. 한가지 이점은 2PC에 의존하지 않고 각각의 업데이트에 대해 이벤트가 게시되는 것을 보장한다는 것이다. 또한, Application은 Business Level 이벤트를 게시하므로 추론할 필요가 없다. 이 접근법의 한가지 단점은 개발자가 이벤트 게시를 기억해야 하므로 잠재적으로 오류가 발생하기 쉽다. 이 접근법의 한계는 일부 NoSQL 데이터베이스를 사용하는 할 때, 제한된 트랜잭션과 쿼리 기능으로 인해 구현이 어렵다는 것이다.

이 접근법은 Application이 상태와 이벤트 게시를 업데이트 하기 위해 로컬 트랜잭션을 사용함으로써 2PC 필요성을 없애준다. 이제 Application이 간단히 상태를 업데이트하도록 함으로써 원자성을 달성하는 접근법에 대해 살펴보자.

Mining a Database Transaction Log
(데이터베이스 트랜잭션 로그 마이닝)

2PC없이 원자성을 달성하는 또다른 방법은 데이터베이스의 트랜잭션이나 커밋 로그를 조사하는 Thread나 Process에서 이벤트를 게시하는 것이다. Application은 데이터베이스를 업데이트 하고, 변경된 결과는 데이터베이스 트랜잭션 로그에 기록된다. Transaction Log Miner Thread나 Process가 트랜잭션 로그를 읽어서 Message Broker에 이벤트를 게시한다. 다음 다이어그램은 디자인을 보여준다.

사용자 삽입 이미지


이러한 접근법의 한 예로, LinkedIn DataBus 오픈소스 프로젝트가 있다. DataBus는 Oracle의 트랜잭션 로그를 조사하고, 변화에 따른 이벤트를 게시한다. LinkedIn은 다양한 파생 데이터 저장소와 시스템의 기록이 일치하도록 하는데 DataBus를 사용한다.

또다른 예는 Managed NoSQL 데이터베이스인 AWS DynamoDB의 스트림 메커니즘이 있다. DynamoDB 스트림에는 지난 24시간동안 DynamoDB 테이블에서 아이템에 이루어진 변경 사항(생성, 변경, 삭제 작업)에 대한 수행 시간 순서가 포함되어 있다. Application은 스트림에서 이러한 변경 사항들을 읽을 수 있고, 예를 들어, 그 변경 사항들을 이벤트로 게시할 수 있다.

트랜잭션 로그 마이닝에는 여러 가지 장점과 단점이 있다. 한가지 장점은 2PC없이 각 업데이트에 대해 이벤트가 게시된다는 것이다. 트랜잭션 로그 마이닝은 또한 Application의 비즈니스 로직으로부터 이벤트 게시 부분을 분리함으로써 Application을 단순화 할 수도 있다. 주요 단점은 트랜잭션 로그의 형식이 각 데이터베이스에 따라 다르고, 심지어 데이터베이스 버전 간에 변경될 수도 있다는 것이다. 또한, 트랜잭션 로그에 기록되어 있는 low-level update에서 high-level business event를 리버스 엔지니어링하는 것이 어려울 수도 있다.

트랜잭션 로그 마이닝은 Application이 데이터베이스 업데이트 한가지만 하게 함으로써 2PC의 필요성을 없애준다. 그럼 이제 업데이트를 제거하고, 단지 이벤트에만 의존하는 다른 접근법에 대해서 살펴보자.

Using Event Sourcing
(이벤트 소싱 사용)

이벤트 소싱은 지속적인 비즈니스 엔터티에 근본적으로 다른, Event-Centric 접근방법을 사용하여 2PC없이 원자성을 달성한다. 엔터티의 현재 상태를 저장하는 대신, Application은 상태가 변화된 이벤트의 순서를 저장한다. Application은 이벤트를 재생함으로써 이벤트의 현재 상태를 재구성한다. 비즈니스 엔터티 상태가 변경될 때마다, 새로운 이벤트가 이벤트 리스트에 추가된다. 이벤트를 저장하는 것은 단일 작업이기 때문에 본질적으로 원자적이다.

이벤트 소싱이 어떻게 동작하는지를 보기 위해서 Order 엔터티를 예로 들어보라. 전통적인 접근방식에서는 각 주문은 ORDER 테이블의 행과 ORDER_LINE_ITEM 테이블의 행에 맵핑된다. 그러나, 이벤트 소싱을 사용할 때에는 Order Service는 상태 변경 이벤트 (Created, Approved, Shipped, Calcelled)의 형태로 Order를 저장한다. 각 이벤트는 Order의 상태를 재구성하는데 충분한 데이터를 포함하고 있다.

사용자 삽입 이미지

이벤트는 이벤트 데이터베이스인 Event Store에 지속적으로 저장된다. 저장소는 엔터티 이벤트들을 추가하고 검색할 수 있는 API를 가지고 있다. Event Store는 또한 이전에 설명한 아키텍처에서 Message Broker처럼 동작한다. Event Store는 서비스가 이벤트를 구독할 수 있도록 해주는 API를 제공한다. Event Store는 모든 관심있어하는 구독자들에게 모든 이벤트를 전달한다. Event Store는 Event-Driven Microservice Architecture의 백본(Backbone)이다.

Event Sourcing은 몇가지 장점을 가지고 있다. Event-Driven Architecture를 구현할 때, 주요 문제점들 중 하나를 해결하고 상태가 변경될 때마다 이벤트를 안정적으로 게시할 수 있다. 결과적으로, Microservice Architecture에서 데이터 일관성 문제를 해결한다. 또한, 도메인 객체가 아닌 이벤트를 지속적으로 저장하고 있기 때문에 객체-관계 임피던스(비율) 불일치 문제를 피할 수 있다. Event Sourcing은 또한 비즈니스 엔터티에 일어난 변경에 대해 100% 신뢰할 수 있는 감사 로그를 제공하고, 특정 시점의 엔터티 상태를 결정하는 임시적인 쿼리를 구현할 수 있다. Event Sourcing의 또다른 주요 장점은 비즈니스 로직이 이벤트를 교환하는 비즈니스 엔터티와 느슨하게 결합되어 있다는 것이다. 따라서, Monolithic Application을 Microservice Architecture로 쉽게 마이그레이션할 수 있다.

Event Sourcing은 몇가지 단점이 있다. 프로그래밍 스타일이 다르고, 익숙하지 않기 때문에 학습 곡선이 있다. 이벤트 저장소는 Primary Key(기본 키)로 비즈니스 엔터티를 직접 조회하는 경우만 지원한다. 쿼리를 구현하기 위해서는 Command Query Responsibility Segregation(CQRS:데이터를 변경하는 Command를 데이터를 읽어들이는 Query와 분리하는 아키텍처 패턴-CRUD중에서 Read와 실제 데이터를 변경하는 CUD를 분리하는 분산 환경에서 사용. 예를 들어 Read는 Cache를 사용하고, CUD가 일어나는 시점에 Cache를 업데이트 하는 방식이 이에 해당함)을 사용해야 한다. 따라서, Application은 결과적으로 일관된 데이터를 처리해야만 한다.



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

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

2017년 4월 1일. 만우절.

우리 가족은 아침부터 느긋하게 대전에 내려갈 준비를 했다. 대전 외가를 방문하기 위해서 선물을 하나 준비했다. 그것은 바로 우리 가족이 사용하던 거실에 있던 쇼파.
 
14층 아파트에서부터 1층에 주차해 놓은 차까지 열심히 날랐다. 너무 오랜만에 힘을 써서 오른쪽 등짝 근육이 꼬일 정도로. 숨을 쉴 때마다 뜨끔한 통증이 나를 울렸다. 역시 평소에 운동을 할 껄 그랬나 보다.(-.-) 약국에서 파스를 사서 3장 연짱 붙인 것은 결혼하고 12년 만에 처음이다. 얍실한 몸매지만, 힘쓰는 건 자신 있었는데. 흑. (물론 나만의 생각이다.)

7인승 올란도 2열까지 접어야 겨우 쇼파를 뒤에 실을 수 있었다. 문제는 아이들이 앉을 자리가 없었다는 것. 그래서 예람이와 예린이는 그냥 쇼파에 앉아서 대전까지 가야 했다.

솔직히 나는 은근 소심하다. 그래서 고속도로를 타고 가다가, 아이들이 안전벨트를 메지 않은 사실을 들켜서 벌금과 벌점을 받게 될까봐 국도로 가자고 주장했다. 그런데 우리 마님도 은근 소심하다. 적극적으로 동의했다. 생각보다 길이 막히지 않아서 약 3시간 반 정도 후에 대전 유성에 도착했다.

대전 유성에 진입할 즈음, 뒷자석에서 "언제 도착해?"라고 수시로 물어보며 정신 사납게 보채던 우리 따님. 뭔가 얘기를 하다가 만우절 이야기를 했다. 나는 또 감탄하지 않을 수 없었다.
"아니, 우리 딸. 만우절도 알아?"
"당연하지. 거짓말해도 되는 날이잖아?"
"오호라! 그렇취~"
이때부터 나의 전성 시대(?)에 있었던 만우절 에피소드 강의가 시작되었다.
"캬~ 아빠가 어렸을 때는 만우절날 수업시간에
선배들하고 자리바꾸고 선생님한테 얻어 맞고,
옆반하고 자리바꾸고 선생님한테 얻어 맞고,
선생님들께 선생님 찾는 연락왔다고 구라치고 교무실로 돌려보냈다가 얻어 맞고, 기타 등등등."
이상하게 이야기의 끝은 얻어 맞는 걸로 정리됐지만, 결론은 "공식적으로 거짓말 해도 되는 날!"이라고 알려줬다.

그런데, 똘똘한 우리 딸.
바로 돌직구를 하나 날렸다.
"엄마! 엄마는 너무 날씬하고 정말로 예뻐!"
어머. 아니 얘가, 겁도 없이, 감히.....(-.-)
운전하는 도중에, 순간 움찔했다.
옆자리에 앉은 마님께서 딸아이가 던진 돌직구를 받아주는 포수가 될지, 받아치는 타자가 될지 걱정되어 돌아보니, 다행히 주무시고 계셨다. 아 정말, 겁나게 다행이었다. 그런데 지금 생각해 보니 왜 내가 놀라야 하는 거지? 아, 나 엄청 소심해졌구나.

사랑하는 이쁜 우리 딸, 예린아.
아무리 사실에 근거한 돌직구(?)라도, 던질 때는 사람과 상황을 봐가면서 해야 한단다.
그리고 가끔 커브나 싱커, 슬라이더 같은 것도 던지고 그래라.
엄마는 너를 너무너무 사랑하지만, 그럼에도 불구하고 엄마 심기가 불편해지면 아빠가 심히 곤란해 진단다.
나 좀 살려됴!
받은 트랙백이 없고, 댓글이 없습니다.

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

Event‑Driven Architecture

많은 어플리케이션에서 솔루션은 Event Driven Architecture를 사용하는 것이다. Event Driven Architecture에서는 비즈니스 엔터티를 업데이트하는 경우와 같은 주목할 만한 어떤일이 일어날 때, 마이크로서비스가 이벤트를 발행한다. 다른 마이크로서비스는 이러한 이벤트 구독을 신청한다. 마이크로 서비스가 이벤트를 받았을 때(구독 신청한 이벤트를 수신했을 때), 자신의 비즈니스 엔터티를 업데이트할 수 있게 되므로 더 많은 이벤트를 발행할 수 있게 될 것이다.

여러 서비스에 걸쳐 있는 비즈니스 트랜잭션을 구현할 때 이벤트를 사용할 수 있다. 하나의 트랜잭션은 여러 단계로 이루어져 있다. 각 단계는 비즈니스 엔터티를 업데이트 하고, 다음 단계를 Trigger하는(작동시키는) 이벤트를 발행하는 마이크로서비스로 이루어져 있다. 다음의 순차적인 다이어그램은 주문을 생성할 때, 이용 가능한 신용 한도를 체크하기 위하여 어떻게 Event Driven 접근법이 사용되는지를 보여준다. 마이크로서비스는 Message Broker를 통해 이벤트를 교환한다.

  1. Order Service는 NEW 상태의 주문을 생성하고, Order Created 이벤트를 발행한다.

사용자 삽입 이미지

  2. Customer Service는 Order Created 이벤트를 구독하여 주문에 대한 신용 한도를 예약하고, Credit Reserved 이벤트를 발행한다.

사용자 삽입 이미지

  3. Order Service는 Credit Reserved 이벤트를 구독하여, 주문 상태를 OPEN으로 변경한다.

사용자 삽입 이미지


더 복잡한 시나리오에서는 고객의 신용한도를 체크하는 동시에 재고를 예약하는 것과 같은 추가적인 단계가 포함될 수 있다.

(a) 각 서비스가 데이터베이스를 원자적으로 업데이트하고, 이벤트를 발행한다. -- 나중에 다시 이야기하기로 하자.
(b) Message Broker는 이벤트가 최소한 한번은 전달되도록 보장하고, 그런 다음 여러 서비스에 걸쳐져 있는 비즈니스 트랜잭션을 구현할 수 있다.

이것은 ACID 트랜잭션이 아니라는 것에 주목하는 것이 중요하다. 최종 데이터 일관성과 같은 훨씬 더 약한 보장을 제공한다. (ACID에서와는 다르게 최종적으로 데이터가 일관성을 유지하기만 하면 된다는 의미.) 이러한 트랜잭션 모델을 BASE 모델이라고도 한다.

여러 마이크로서비스가 소유한 데이터를 pre-join(사전 조인)하는 실체화된 뷰를 유지 관리하기 위해 이벤트를 사용할 수도 있다. 뷰를 유지 관리하는 서비스는 관련있는 이벤트를 구독하여 뷰를 업데이트한다. 예를 들어, Customer Orders View를 유지 관리하는 Customer Order View Updater Service는 Customer Service와 Order Service에서 발행한 이벤트를 구독한다.

사용자 삽입 이미지


Customer Order View Updater Service가 Customer나 Order 이벤트를 받을 때, Customer Order View Datastore를 업데이트 한다. MongoDB와 같은 문서 기반 데이터베이스를 사용하여 Customer Order View를 구현하고, 각 Customer별로 하나의 문서로 저장할 수 있다. Customer Order View Query Service는 Customer Order View Datastore에 질의하여 고객과 고객의 최근 주문 내역을 처리한다.

Event-Driven Architecture에는 여러 가지 이점과 단점이 있다. Event-Driven Architecture는 여러 서비스에 걸쳐 있는 트랜잭션을 구현할 수 있고, 최종적인 데이터 일관성을 제공한다. 또다른 이점은 어플리케이션이 실체화된 뷰를 유지 관리할 수 있다는 것이다. 한가지 단점은 ACID 트랜잭션을 사용할 때보다 프로그래밍 모델이 훨씬 복잡하다는 것이다. 종종 어플리케이션 수준의 오류를 복구하기 위해서 보상 트랜잭션을 구현해야만 한다. 예를 들면, 신용한도 확인이 실패할 경우에는 주문을 취소해야만 한다. 또한 어플리케이션은 일관성이 없는 데이터를 처리해야 한다. 운영중인 트랜잭션으로 인해 생성된 변경 사항들을 볼 수 있기 때문이다. 어플리케이션이 아직 업데이트 되지 않은 실체화된 뷰에서 데이터를 조회했을 경우, 데이터 불일치가 발생할 수 있다. 또다른 단점은 이벤트를 구독하는 쪽에서 중복된 이벤트에 대해 감지하고 무시해야 한다는 것이다.

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

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