Event 기반 Microservices - Event Sourcing 및 CQRS

현재 IT업계에서는 기존 Monolithic 방식의 개발방식에 대한 많은 문제점을 인식하고 있는 상황입니다. 그에 따른 대안으로 Microservice Architecture Serverless Architecture등 다양한 방안 찾고 있지만 일반 기업에서 선뜻 아키텍처를 바꾸지는 못하는 상황입니다.

 첫 번째 이유는 IT서비스 전문 기업 외에는 아직 일반기업에서 적용한 성공적인 사례가 찾아보기 힘든 점이 있고, 기업 내 자체 IT 인력이 이러한 MSA에 대한 이해도나 실제 구현 및 적용하기 까지 지식이나 경험이 부족한 상태입니다.

두 번째로 이러한 부분을 해결하기 위한 솔루션 제품들이 아직 성숙되지 않은 문제도 있습니다. 하지만 불과 몇 년만 C/S 환경에서 웹 기반 아키텍처로 순식간에 변화했듯이 웹 기반 및 멀티채널 디바이스를 지원하는 상황에서 기존 모놀리틱 방식의 시스템이 점점 비대화 되는 문제점을 해결할 수 있는 유일한 방안으로서 API 기반의 MSA의 활성화를 기대해 봅니다.

 저희 회사도 이러한 문제를 해결하기 위하여 솔루션을 준비하고 미래의 변화에 대응하고 있습니다. 그 첫 번째로 기업용 API 서버인 DBridge 를 출시하였고, 기술적인 문제를 계속 고민, 보완하여 발전시키고 있습니다.

이번 아티클에서는 이벤트 기반의 Microservices 에 대해 알아보겠습니다.

 

Event Driven Microservices

오늘날 기업 업무 시스템은 수많은 변화에 빠르게 대처해야 합니다. 각 서비스를 빠르게 개발하는 것도 중요하고 각 서비스의 조합이나 업무 flow도 자주 변경 될 수 있습니다.

또한 기본적으로 MSA 방식으로 구현된 각 서비스는 별도의 저장소를 사용하는 경우가 많고 필요에 따라 분산된 데이터 저장소의 일부 값을 일치시켜야 하는 경우도 있습니다. 이는 transaction 처리의 문제로 귀결되며, [모놀리틱 시스템에서 MSA로 전환] 이라는 글에서 언급한 것과 같이 ‘Try Again Later’ 또는 ‘Abort the Entire Operation’을 선택해서 처리하여야 합니다. 일반적인 상황이라면 ‘Try Again Later’를 선택해서 처리하는 것이 일반적인 경우입니다.

그리고 분산 저장소를 고려하는 경우 데이터의 동기화 문제 또한 발생할 수 있습니다.

 이러한 문제점을 해결하기 위한 방안으로 Event Driven Microservices를 생각할 수 있습니다.

 

좀더 일반적인 업무에 적용하여 예를 들어보겠습니다.

 온라인쇼핑몰 회사에서 상품 주문이 수행이 되면 다음과 같은 로직이 수행될 수 있습니다.

 

 

API기반으로 해당 서비스를 작성한다면  첫번째 고민이 어느 단위로 서비스를 개발하여야 하는지 고민입니다. 상품주문 서비스를 개발하고 그 안에 상품정보 기록, 출고 지시, 임시 매출현황 변경 로직등을 모두 포함 시켜야 하는지, 아니면 상품 주문 정보 기록, 출고 지시 등 서비스를 나누어서 개발하고 이를 순차적으로 호출하여 통합하는 서비스를 또 다시 만들어야 하는지 1차적으로 고민하게 되어있습니다.

 MSA기반으로 생각하면 서비스는 되도록 작은 업무단위로 개발되어야 합니다.  즉 사용자의 주문 정보를 주문 Table에 기록을 하고 기본업무는 완료하는 것으로 끝내는 것이 이상적입니다.. 그 뒤에 출고 지시 업무는 상품주문 서비스내에 포함시키는 것이 아니라 상품 주문 서비스 완료 후 출고 지시 서비스가 수행이 될 수 있도록 합니다. 경우에 따라 출고 지시 뿐만 아니라 임시 매출현황 변경 통보를 해야 할 수 도 있고, 특정 상품 또는 특정 사용자 주문인 경우는 별도의 CRM 서비스를 호출 할 수 도 있습니다. 이렇게 업무변경이 일어날 경우 많은 상황변화에서 각 서비스를 통합하는 하나의 서비스 또 작성하는 것은 비효율이 일어날 가능성이 높습니다.

 이러한 업무가 변경될 때마다 상품 주문 서비스를 계속 수정을 한다면 유지보수도 힘들고 여러 서비스간의 종속성이 때문에 일어날 수 있는 문제점이 새롭게 발생할 수 있기 때문입니다.

 문제점을 해결하기 위한 방안으로 Event 기반의 Service 환경이 구축을 생각할 수 있습니다.

 즉 상품 주문 서비스가 호출이 되면. 주문 정보를 DB에 기록하고  주문 서비스가 실행되었다는 event 를 발생시키고  주문서비스 이벤트가 실행되었는지 체크하는 Event Listener 가 그 event를 인식하여 출고지시 서비스를 수행하도록 하면 됩니다.

 이와 동시에 특정 상품이 주문되면 SMS 로 통보해야 한다면 이 event를 체크해서 SMS 호출하는 서비스를 호출하면 된다.

 이러한 방식은 각 서비스를 Event로 묶어서 loosed coupling을 유지하면 서비스의 확장성을 뛰어나게 할 수 있는 장점을 가지고 있습니다.

 

Even Sourcing

이러한 Event 기반의 아키텍처에서 자주 언급되는 용어로 Even Sourcing이라는 개념이 있습니다.

Micro Service Architecture의 전도사 및 소프트웨어 아키텍처로 유명한 Martin Fowler가 이미 2005년에 자신의 홈페이지에서 언급하였습니다.

Event Sourcing은 어플리케이션의 모든 상태 변화를 순서대로 이벤트로 보관하여 처리하는 개념으로 소개합니다. 이렇게 모든 상태를 이벤트의 흐름으로 처리하므로 서 어플리케이션 개발을 간소화하고 분산환경에 적절히 대응할 수 있는 개념입니다

 어플리케이션 개념으로 다음과 같은 이벤트 목록 예를 들겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 멤버생성 이벤트
createMember : { "userid":"skkim""email":"skkim@test.com""addr","seoul"}
 
// 제품주문 이벤트
orderProcut : {"productId":"AD42323424""datetime":"20150105 140533""userid","skkim"}
 
// 멤버생성 이벤트
createMember : { "userid":"flowerX""email":"flowerX @comp2day.com""addr","tokyo"}
 
// 멤버삭제 이벤트
deleteMember : { "userid":"skkim"}
 
// 제품주문 이벤트
orderProcut : {"productId":"AD423233424""datetime":"20150106 105010""userid","skkim"}
cs


 

위의 모든 이벤트는 시간 순으로 기록이 되며 각 서비스는 자신이 필요한 이벤트만 바로 보고 있다가 최신의 상태만 유지면 됩니다.

즉 회원관리 서비스는 회원의 생성 삭제, 또는 변경 이벤트만 바라보면서 회원의 최신정보 (snapshot)을 가지고 빠르게 최신정보를 유지할 수 있습니다.

 또한 상품 관련 서비스는 상품의 주문, 배송 등 이벤트만 참조(Listening)하고 있다가 최신 상태를 유지하면 됩니다.

 이러한 Event Sourcing이 완벽이 동작하려면 모든 이벤트는 기록되어야 하고, 이벤트를 받지 못하는 서비스가 없도록 재전송이 가능한 기반이 되어야 합니다.

 또한 이벤트는 분산환경에서 자신의 서비스 또는 WAS내에서만 받을 수 있는 것이 아니라 전파(Broadcasting)이 되어야 분산된 환경에서도 완벽하게 동작할 수 있습니다.

 Event sourcing의 이러한 특징 때문에 MSA 시스템을 적용할 때 Event 기반으로 구현하면 보다 손쉽게 구현이 가능하며,각 서비스간의 loosed coupling이 가능합니다.

 

CQRS (Command Query Responsibility Separation)

Event Sourcing과 항상 함께 알아두어야 할 개념으로 CQRS가 있으며 간단히 설명하면 Command Query 의 책임을 분리하자는 것입니다.

Command는 일반적인 Database 기준으로 상태를 변경하는 Create, Update, Delete 와 같은 메소드로 생각할 수 있으며, Query 는 단순 데이터를 조회하기 위한 Read 메소드로 생각할 수 있습니다. 전에 설명한 Event Sourcing과 연계시켜 생각해 보면 Event Command 즉 상태 변경되는 경우만 발생하고 그 경우만 기록하면 됩니다. 단순 Query 인 경우는 모델의 정보를 변화시키지 않기 때문에 그 기능을 분리하여 좀더 손쉽게 Event Sourcing Pattern을 적용할 수 있습니다.

또한 Event Sourcing 개념에 의해 생성된 최신 데이터(snapshot) CQRS에서 Query 의 개념으로만 접근하여 조회하기 때문에  로직을 간략화 하고 cache를 통해 조회속도를 손쉽게 개선할 수 있습니다.



 

Event Driven Microservices를 위한 DBridge 

실제 Event Driven Microservices를 구축하기 위한 구현된 제품은 거의 전무한 상태입니다. MSA 서비스를 위한 API 서버인 DBridge 제품을 통해 Event Drive Service 를 구현해 보도록 하겠습니다.

 

시나리오

상품주문” API 호출 후 상품출고지시” API 가 자동으로 호출 될 수 있도록 하고, 2016 10 1일부터 상품주문서비스가 호출 후에 메일발송하는 서비스가 자동으로 수행할 수 있도록 구현

 

위와 같은 시나리오에서는 DBridge API 서버에서는 간략하게 두 가지 이벤트를 추가하면 됩니다.

 

첫번째

상품주문이라는 API 서비스 완료 후 상품출고지시라는 서비스 자동으로 수행될 수 있도록 event 를 등록하는 화면입니다.  “상품주문서비스가 호출 될 때마다 자동으로 상품출고지시서비스가 실행될 수 있는 기능을 제공합니다.

 



두번째

상품주문서비스가 호출 후에 메일발송서비스를 호출하고자 합니다. 단 해달 메일서비스가 2016 10 1일부터 준비되므로 그전에는 수행되지 말고 해당일 이후부터 실행이 되어야 합니다. 그런 경우 아래 화면과 같이 해당 이벤트를 등록하고 시작일을 설정하여 서비스 변동에 개발자가 신경 쓰지 않아도 손쉽게 적용이 됩니다.

 


Java Code로 구현할 수 있는 Filter기능을 통해 다음과 같이 특정 상태인 경우만 선별하여 수행할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import coreframe.data.*;
 
/**
 * 주문량이 100건 이상인 경우만 통보처리
 *
 **/
public class BizEventFilter {
    
    
    public boolean filter(DataSet preOutput, DataSet nextInput) {
        int orderAmt = preOutput.getInt("orderAmt");
 
        // 100건이 넘는 경우만 처리
        if(orderAmt>100) {
            // 주문번호 설정
            nextInput.put("orderId", preOutput.get("orderId");        
            return true;
        }    
        return false;
    }
}
cs

또한 해당 서비스가 더 이상 필요 없으면 기존 로직을 수정하는 것이 아니라 간단히 해당이 이벤트를 삭제하거나 서비스 종료일을 설정하여 손쉽게 업무 변화에 대응할 수 있습니다.

  

이상 Event 기반의 MSA 구축을 위한 개념 및 DBridge API Server 를 통한 예를 들어보았습니다. 아직 API MSA 기반 환경이 생소할지 모르겠지만 조금씩 새로운 환경에 준비하고 대처해 나간다면 디지털 비즈니스 시대에 대응하는 성공적인 기업 또는 개발자로 발전할 수 있기를 기대해봅니다.



참고자료

 

 

New Multi-Channel Dynamic CMS