Windows에서 Docker Web application 개발환경 구축

Docker 나 컨테이너 가상화는 무엇인지 굳이 설명을 하지 않아도 이제는 매우 일반적으로 쓰이는 IT 용어가 되었습니다.

Hybrid 기반의 Cloud 환경 및 Microservices 가 앞으로 인프라 아키텍처로써 발전해 나가고 있는 시점에  컨테이너 기반 가상화의 대표주자인 Docker의 중요성은 다시 설명 드리지 않아도 될 만큼 개발자나 인프라 담당자가 꼭 알아두어야 할 시대가 된것 같습니다.

그래도 추가적인 대략적인 개념이 필요하시면 아래 글을 읽어보시면 도움이 되겠습니다.

 참조 :컨테이너 기반의 가상화 (Docker) [링크]

 이번 아티클에서는 대부분 개발자가 이용하고 있는 윈도우 환경에서 Docker 환경을 구축하고 Tomcat 기반의  web application (war)을 Docker image 로 만들고 실행해 보는 방법을 정리해 보겠습니다.

그전의 Docker  활용예제등은 linux 기반의 centos ubuntu 에서 직접 실행하는 예제나 소개여서 windows 환경에서 동작시킬 때는 생각보다 어려운 점이 많았습니다.

  

Docker 설치

 Centos RedHat OS 에서는 이미 Docker가 기본 설치되거나 yum 통해 편리하게 설치 실행할 수 있습니다.

Docker는 기본적인 Linux Kernel 에서만 동작하기 때문에 Oracle VirtualBox와 같은 OS기반 가상화 기술을 활용하여 Windows MacOS에서는 설치 및 실행합니다.

우선 Docker Toolbox(https://www.docker.com/products/docker-toolbox)를 설치합니다.

 

되도록이면 선택항목을 모두 선택하고 설치하면 됩니다.

 

모두 설치가 완료되면 아래 화면과 같은 프로그램 메뉴가 추가됩니다.

 - Docker Quickstart Terminal :  docker 명령을 이용할 수 있는 terminal

 - Kitematic (Alpha) : docker image를 손쉽게 다운받고 설치 실행할 수 있는 GUI Tool

 

처음에서는 Docker Quickstart Terminal 을 실행할 때 오류가 발생하는 경우가 많아서 아래와 같은 순서로 진행하는 것이 좋습니다. (MacOS 환경에서는 바로 잘 동작합니다. Windows 환경에서도 잘 동작하는 경우가 대부분인데 제 PC에서는 잘 안되는 경우가 많네요.)

 





 - Kitmatic 실행

 - 만약 오류 발생시 [USE VIRTUALBOX] 선택 

 - 실행 완료 후 좌측하단의 DOCKER CLI 실행해서 command 모드 실행

   

내부적으로는 VirtualBox을 통해 Docker 가 실행될 수 있는 OS(boot2docker) 이미지를 통해 실행되는 것인데 VirtualBox boot2docker 이미지가 잘 올라오지 않는 경우가 있습니다.

이런 경우 수동으로 docker 서버 머신을 VirtualBox에 아래 명령으로 설치할 수 있습니다.


 docker-machine -s D:\docker create --driver virtualbox docker

 

-s 옵션은 docker 가상 이미지 및 설정정보가 위치하는 경로이고

맨 마지막 docker virtualbox의 가상VM 의 이름을 설정하는 것입니다.

기존에 docker machine이 있는 경우는 

docker-machine rm docker 

와 같은 명령을 통해 삭제할 수 있습니다.

  

제일 먼저 docker version을 확인해 보시면 docker client server의 버전을 확인해 볼 수 있습니다.

  


tomat web application 이미지 만들기

다음 준비할것을 tomcat에 올릴 war (web applicaitn)  준비해야 합니다

그리고  Dockerfile 이라는 docker 이미지를 만들기 위한 각종 메타정보를 담고 있는 파일을 작성해야 합니다.

 

## 기본이 되는 docker image 
From tomcat:8-jre8

# Maintainer
MAINTAINER "Me <me@gmail.com>"

# Copy to images tomcat path
ADD coreframe-5.0.2.war /usr/local/tomcat/webapps/

  

docker build -t webserver .

 

위 명령을 입력하면 현재 디렉토리의 dockerfile정보를 읽어서 webserver 라는 이름의 docker image를 생성합니다.

 

이제 docker container를 실행 보죠.

 

docker run -it --rm -p 18080:8080 --name firstdocker webserver

위 명령 firstdocer라는 이름을 가지고 webserver 컨테이너를 실행하는 명령이다.

-p 는 포트관련 옵션으로 외부 18080 포트를 container 내부의 8080 포트로 mapping 시켜준다는 의미입니다. 잘 실해이 되면 아래와 같이 Docker Container 를 통해 실행한 web application을 확인해 볼 수 있습니다.

 


 

Maven에서 docker image 생성하기

 

실제 서비스를 목표로 하는 경우는 소스의 변경이 되었을 때 즉각적으로 docker image 를 생성하여 자동화 하고자 하는 경우가 일반적입니다.

java 소스를 build할 때 많이 사용되는 maven에서 docker plugin을 활용하여 web application war를 생성하고 해당 war tomcat image 와 결합된 docker image를 생성하는것에 대해 설명하겠습니다.

 

1) Dockerfile 설정

이번의 경우도 첫번째 작업은 dockerfile을 설정입니다.. 보통 src/main/docker 라는 디렉토리를 만들고 Dockerfile 파일을 생성하여 아래와 같이 설정하시면 됩니다.

 

FROM tomcat:8-jre8
MAINTAINER webplugger

# remove the default tomcat application
RUN rm -rf /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.war

# add the BiVeS-WebApp as the new default web app
COPY coreframe-web-${project.version}.war /usr/local/tomcat/webapps/ROOT.war

 

2) pom.xml 수정

dockerfile를 읽고 실행하기 위해서 몇 가지 추가적인 maven plugin을 설정해야 합니다.

 

 

<plugin>
    <artifactId>
maven-resources-plugin</artifactId>
    <executions>
        <execution>
            <id>
copy-resources</id>
            <phase>
validate</phase>
            <goals>
                <goal>
copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>
${basedir}/target</outputDirectory>
                <resources>
                    <resource>
                        <directory>
src/main/docker</directory>
                        <filtering>
true</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

 

  


<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.4.10</version>
<configuration>
<imageName>cyberx/${project.artifactId}</imageName>
<dockerDirectory>${basedir}/target</dockerDirectory>
</configuration>
</plugin>

 

3) mvn.bat 수정

set DOCKER_HOST=tcp://{docker ip주소}:2376

set DOCKER_MACHINE_NAME=default

set DOCKER_TLS_VERIFY=1

set DOCKER_TOOLBOX_INSTALL_PATH=d:\Program Files\Docker Toolbox

set DOCKER_CERT_PATH=C:\Users\사용자이름\.docker\machine\machines\default

위와 같은 설정을 추가 설정이 필요합니다.

기본적으로 docker plugin JDK 7이상을 사용해야 하므로 maven JAVA_HOME 환경도 그에 따라 설정해주어야 합니다.

 

DOCKER_HOST는 자신의 docker machine의 ip 주소에 맞추어서 설정을 하고 port는 일반적으로 2375 또는 2376인데 본인의 윈도우 환경에서는 2376으로 설정되어 있었습니다.

DOCKER_TOOLBOX_INSTALL_PATH  DOCKER_CERT_PATH 경로는 본인의 docker toolbox 설치 경로 및 사용자 경로에 맞추어 설정을 수정하시면 됩니다.

  

mvn clean package docker:build

 

docker run -d -p 28080:8080 --name coreframe cyberx/coreframe-web

 

 

Docker image 등록하고 가져오기 (push/pull)

한번 만들어진 docker image는 재활용 성을 높이기 위해 저장소에 등록하고 편리하게 가져다 쓸 수 있습니다.

우선 별도의 개인적인 register 를 만들 수 도 있지만 https://hub.docker.com/ 을 통해 편리하게 저장소를 이용할 수 있습니다.

 아이디와 이메일, 패스워드 등록 한 후 email 통한 confirm이 끝나면 바로 이용할 수 있습니다.

  

이미지 등록은

docker push 계정명/이미지이름 

 

반대로 image 를 가져올 때는 

docker pull 계정명/이미지이름 

 

으로 하면 image 내용을 가져올 수 있습니다.

 Docker 의 images 들은 하나의 파일이 분산돼서 저장되고 다운로드 되기 때문에 추후 push 및 pull 할 때 오랜 시간이 걸리지 않습니다.

  

마무리

Docker 기술은 Linux의 컨테이너 가상화 기술인 LXC로 부터 파생되어 나온 기술이라 아무래도 Window Mac 환경에서는 약간 불편하고 생각처럼 잘 안 되는 경우가 있습니다.

또한 외국 자료 또한 Linux 기반환경에서 직접 작업하는 경우가 많아 windows에서 환경 설정 및 war 이미지 생성관련 자료는 많이 부족한 상태입니다.

Monolithic 방식의 거대한 web application을  Docker  같은 방식으로 image 를 생성하여 관리하는 것은 Docker의 많은 장점을 사용하지 못할 수 있습니다.

Microservices 와 같이 작은 개념은 여러 서비스를 Docker 컨테이너 기술을 사용한다면 기존 Monolithic 방식보다 훨씬 사용하기 편하고 개발 및 배포의 life cycle을 단순화 하고 빠른 변화에 대처가 가능합니다.

 메인프레임에서 Unix 서버를 거쳐 이제는 Linux 기반의 OS로 많은 기업들이 Platform을 변경하고 있으며

Microservices 개념처럼 작은 서비스를 독립적이면 성능 부하를 주지 않는 Docker는 앞으로 일반적인 기술이 될것 으로 보입니다.

 2017년 새해에 새로운 기술을  열린 마음으로 적극 활용해 보면 좋을 것 같습니다.

 

 

 


New Multi-Channel Dynamic CMS

마이크로 서비스 아키텍처를 위한 Frontend 개발패턴

 그 동안 마이크로 서비스 아키텍처 관련 내용을 소개하고 관련 솔루션을 준비하면서 항상 아쉬운 부분이 있었습니다. 우선 기존에 다루었던 마이크로 서비스관련  목록을 다시 나열해 보겠습니다.

 

주로 마이크로 서비스 아키텍처 자체 및 비즈니스 로직이 구현에 대한 글들이 많습니다. 그러나 실제 적용하기 위해서 일반 개발자나 현업이 생각해 보는 부분은 UI frontend 구현에 대한 고민입니다.

 일반적으로 마이크로 서비스 방식에서 각 채널 별 Frontend 관련 개발 패턴은 API기반인 JSON  형태 데이터를 AJAX  방식 호출을 통해 Single Page Application( SPA)을 구성하는 개발방식을 그동안 지향하였습니다. 그에 따른 Angular.js나 Ember.js와 같은 JavaScript MVC framework 사용을 추천한 상황이고요.

 하지만 현실적으로 AJAX로 도배된 상태로 전 사이트를 구축하기 도 힘들고 모든 서비스를 ajax 호출하는 client 구현 및 이용은 어려운 점이 많습니다.

MSA방식을 통한 비즈니스 로직이나 업무로직은 이상적으로 구축할 수 있으나 실제 각 front-end 쪽은 MSA 방식을 지향하는 현실적인 최적의 구축 방안이 많이 부족한 상태입니다.

 Baas(Backend as a Service) 관련 솔루션이나 API 구축 업체는 각 채널에서는 HTTP를 넘나드는 Direct Public API 방식의 호출을 지향하고 있지만 다음과 같은 문제점을 가지고 있습니다.

 

 Stateless 방식 API

 - MSA에서 API Gateway 서버나 Baas 단에서는 상태를 유지하지 않기 때문에 매번 Security Key 과 같은 고유 키 값을 전송

 - 웹에서 session 유지 기능을 구현하기 어려운 점이 있어서 매번 API 호출 시 사용자 id를 넘기거나 위 기능을 할 수 있는 비즈니스 로직을 별도로 개발하는 문제가 발생

 

보안문제

 - 무상태(stateless)로 해당 비즈니스 로직을 처리해야 하기 때문에 서비스 개발 시 그 수간 필요한 모든 데이터를 입력 받아서 처리

 - 특정 사용자 아이디나 주요 키값 등이 노출되어 보안상 문제가 발생

 - ex) 나의 결제내역 API 호출 시 나의 ID를 의미하는 user id 또는 그에 대응되는 사용자 고유 키값을 넘기는데 이 부분은 Http Proxy등을 통해 변조될 가능이 높음.

 

서비스의 결합의 성능 문제

 - 개별단위로 된 API를 조합해서 filtering 된 데이터를 이용하고자 하는 경우 client 단에서 모든 데이터를 처리하면 성능이 늦어진다.

 - 개별적 API 를 결합하여 서비스하는 경우 저 사양 client channel (ex 모바일 웹) 문제점 발생

 

최적화

 - 각 채널 별 최적의 UI 용 최적의 데이터 구성의 어려움.

-   UI 관련 최적화된 기능 구현을 위한 로직 구현의 어려움.

 

 

 

 

BFF : Backend for Frontend

 

BFF는 Bank of America, ThoughtWorks 등 Cloud 서비스 관련 전문가인 Phil Calcado 에 의해 최초 정의된 용어로 Backend for Fronted 의 약자입니다.

즉 frontend 만을 위한 backend 시스템 패턴으로 이해할 수 있으며, UI API Data 연계를 위한 중앙통제 성격의 backend 기능만을 구현하여 각 채널 별 UI 시스템 구성을 최적화 할 수 있도록 해주기 위한 구축 패턴으로 이해하면 되겠습니다.


BFF 패턴을 적용하는 장점은 위에 언급된 Direct API 호출 client 구현의 문제점을 대부분 해결할 수 있는데 있습니다.

필요한 데이터를 API 호출을 통해 이용하고 session관리가 가능하며 각 UI 채널을 위한 최적의 Presentation 코드등 (HTML,CSS,JSON)을 관리하고 UI 비스를 담당하는 역할로 볼 수 있습니다.

위의 경우와 같이 필요한 데이터는 필요 API를 호출할 수 있으며 미리주요 코드성 데이터등을 적재(load)하여 성능을 개선하거나 UI 개발의 확장성을 높일 수 있습니다.

따라서 새로운 서비스 채널이 생기면 사용자 접점의 frontend 개발을 BFF 방식으로 처리하고 손쉽게 시스템을 확장할 수 있는 장점을 가지고 있다. 물론 비즈니스 로직은 MSA 기반의 API로 되어 있다면 재활용 성을 극대화 하여 생산성을 향상시킬 수 있습니다.

 

구현 기술

MSA API구현을 개발자가 원하는 기술로 구현할 수 있듯이 BFF backend 서비스는 어떠한 기술을 써도 상관이 없습니다.

database 나 각종 Middleware에 대한 기술 종속성이 없으므로 frontend관련 기술에 집중할 수 있으며 기존 WAS(Web Application Server)처럼 방대한 구축을 하지 않아도 가벼운 web server 로 구축이 가능한 장점을 가지고 있습니다.

 

 실제 기술 

 - J2EE JSP.Servlet 으로만 구현

 - NodeJS를 통한 구현

 - PHP 기술로 구현

 

어떠한 기술을 이용해도 상관없지만 사실 어떠한 기술이 최적화되어 잘 사용될 수 있을지는 또 다른 문제이긴 합니다.

 구현되는 API를 호출하고 session 관리 등을 하기 위해서는 생각하지 못한 고려사항들이 아직 많이 남아있습니다. 실제 저희 회사 시스템 일부 및 다른 기업의 웹서비스 구축에서 BFF 패턴을 이용해 보았지만 아직도 더 많은 연구를 통해 저희 솔루션(DBridge 및 coreFRAME)에 적용되고 확장해야 할 부분이  많아 남아있는 상태입니다.

 

BFF 패턴도 MSA 와 마찬가지로 아직 효과적 UI Channel을 구성하기 위한 하나의 패턴으로 좀더 다듬어 져야 할 문제점을 가지고 있지만, 몇몇 국내 기업들이 Cloud 기반 또는 PaaS 기반의 변화에 대한 움직임을 보이면서 2~3년내 IT 산업 변화에 대응하며 준비되어야 할 기술로 판단됩니다.


You never change things by fighting the existing reality.

To change something, build a new model that makes the existing model obsolete. 


Buckminster Fuller


 

 

 

 

New Multi-Channel Dynamic CMS

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

모놀리틱 시스템에서 MSA로 전환


SW산업은 그 어느 산업보다 빠른 속도로 변하고 있다고 느낄지 모르겠지만, Software 개발자로서 IT밒 소프트웨어 개발 트랜드를 면면히 살펴 본다면 사실 하나 하나 계단을 밟아가는 듯이 점진적으로 발전을 해왔다 그 동안 계속   필자가 다루고 있는 Micro Service Architecture(이하 MSA)도 지금 개발 패러다임에서 급진적으로 보일지 모르겠지만,   그 동안으로 개발역사를 살펴 본다면 하나씩 하나씩 점진적으로 발전되어 나온 하나의 결과물이다



MSA는 기본 사상은 Service Oriented Architecture (SOA) 사상에서 출발하여 발전 하고 있다. SOA도 기존에 있었던, 1990년대 CORBA( Common Object Request Broker Architecture) 및 RPC( Remote Procedure Call)등 개념을 확장하여 점진적으로 발전하여 나온 사상이다. 이 모든 것이 급변하는 실 세계를 보다 빠른 속도로 반영하고, SW를 개발하기 위한 목적이며, 각각의 이론에는 그 이론을 뒷받침 하기 위한 여러 구현체들이 존재하였다

SOA 환경에서는 ESB (Enterprise Service Bus) 관련 제품이 주를 이루면  SOA 관련 업체들이 많이 장점을 강조하며 새로운 변화를 이끌려고 하였지만 실제 개발자가 느끼기에는 ESB도 기본 EAI 솔루션과 크게 틀리지 않고 XML 및 SOAP이라는 무거운 Protocol로 인해 성능 문제 및 구현이 대단한 어려운 문제점을 내포하고 있었다.

또한 Java 진영에서는 SOAP과 WSDL ,UDDI등 다양한 Web Services 스펙을 지원하기 위한 여러 API 들이 나왔지만, 객체지향적인 정보를 XML 로 표현하기에는 너무 무겁고 변환방식으로 매끄럽지 못한 문제점을 가지고 있었다.

그 후로 REST방식 웹 개발이 보편화 되면서 기존 XML/SOAP 기반으로 서비스 시장의 대부분을 잠식하면서 모든 Platform에서 표준 API 통신 protocol로 자리 잡고 있으며, 여러 분야에서 IT 기술을 발전시키고 있다 .  

사실 처음부터 MSA 사상으로 설계하고 시작하기 매우 어렵다 . 기존 모놀리틱 기반의 시스템이 존재하는 경우가 대부분이고, 이를 바탕으로 Service 개념을 도입하고자 하는 고객이 대부분이다
오늘은 이런 기존 고객이 가지고 있는 모놀리틱 기반 시스템에서 어떻게 Service 를 나누면 좋을지, 그리고 그렇게 나누기 위해 고려되어야 할 사항들이 어떤 게 있는지 알아보자


좋은 서비스(Good Service)란?

우선 각각의 서비스로 분리하기 위해서는 좋은 서비스에 대한 정의가 필요하다.
좋은 서비스는 다음 2가지 사항만 만족시키면 된다.
  • Loose Coupling
  • High Cohesion
즉 서비스들 간에는 서로 연관관계가 적어야 하면, 서비스 내적으로는 높은 응집력을 가지고 있어야 한다. 아래 설명하는 내용은 loose coupling 조건을 갖추기 위해 필요한 모델관의 연관관계를 최소화 하기 위한 방법들을 설명하겠다.


FK 관계 연결 끊기
첫 번째 조건으로 loose coupling이 되기 위해서는 데이터 관계부터 서비스간의 종속관계를 끊어야 한다. 첫번째 모델간 서비스간 연결관계를 제거하기 가장 어려운 첫번째 문제는 DBMS 테이블간의 Foreign key에 의한 연관 관계이다. 하지만 Foreign Key 연결 관계를 끊기는 DBMS 환경에 익숙한 개발자에게서는 매우 어려운 일이다.

Building  Microservices 책에 의하면 이러한 부분은 DB 및 서비스를 분리하고 서로 필요한 데이터에 대해서는 API call을 통해 처리하라고 말하고 있다. 올바른 MSA 서비스 구축을 위해 약간의 성능을 희생할 수 있다고 하지만, 과연 고객이 이 부분을 수용할 지는 미지수다

우선 가장 이상적인 연결과계를 표현하는 방법은 URN(Uniform ResourceName)을 통한 표기 방법이다. 가량 데이터중 다른 회원의 아이디를 참조하는 경우라면 urn:li:member:123 과 같은 스키마 정보및 테이블 정보 아이디를 모두 포함한 URN 형태로 표기하는 것이 좋다. (LinkedIn's architecture : http://www.slideshare.net/parikhk/restli-and-deco)


Static 데이터 공유
공통 코드성 데이터를 각 서비스에 서 공유하는 경우 이런 경우까지 API 호출을 통해 데이터를 공유하는 것은 매우 불합리 하다. 대표적인 것은 증권사의 기본적으로 사용하는 종목코드 마스터 데이터이다. 이런 경우 보통 배치성으로 Master code 파일을 매일 새벽에 생성하고 이 데이터가 필요한 각 서비스에서는 이 마스터 파일을 하루에 한번 호출하여 가지고 있다가 이용하는 방식이다.
별도의 공통 코드 테이블에 대한 규칙은 없고, 각 서비스에 필요한 방식으로 구축하여 이용을 한다. 서비스 분리에 대한 문제점이 없으며, 필요한 시기 정확히 데이터를 다운받는다면 불일치 문제도 발생하지 않는다.

공유 데이터
좀더 복잡한 상황으로 들어가보면, 공유되는 데이터가 위의 예시처럼 하루에 한번만 바뀌는 데이터가 아니라, 수시로 바뀔 수 있는 데이터라고 한다면 위와 같은 방법으로 데이터 처리는 불가능 하다. 이러한 경우는 공통 Service 로 구축하여 API 호출을 통해서 이용하는 것외는 방법이 없다. 가량 재무,홍보,분석 서비스에서 각각 고객 데이터가 필요하다면 필요할때마다 고객 정보 API를 호출해서 이용해야 한다. 이렇게 구축함으로서 Data 계층에 대한 종속성도 없애고 필요 데이터 호출 및 권한 처리등 여러 이점을 누릴 수 있지만, 성능에 대한 이슈는 항상 남아 있다.


Transaction
서비스가 분리되면서 가장 첫번째 신경 써야 되는 부분이 Transaction 처리부분이다. Transaction은 기본의 시스템이 하나로 묶을 수 밖에 없었던 이유 중에 중요한 첫 번째 이유이며, 분산 환경 및 MSA 환경에서도 그 처리가 쉽지 않은  요구사항이다

사실 서비스가 분리된  분산환경에서는 Distributed Transaction 을 위해 X/Open Distributed Transaction Processing(DTP) Model (X/Open XA) 스펙이 있지만 이를 지원하기 위한 two-path commit(2PC) JDBC Driver 및 DBMS는 생각보다 많지 않으며 , 이기종간의 DB인 경우는 이런 처리가 더욱 어려운 문제점이 있다.

 Transaction 처리   및 일반적인 DB에서 가장 먼저 나오는 용어이 ACID를 집고 넘어가야 한다. ACID는 (원자성, 일관성,고립성, 지속성) 데이터베이스 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 성질을 가리키는 약어이다.



하지만 이 ACID는 MSA 환경에서는 구현하기 힘들며 ,  그래서 ACID에 대응돼서 나온 이론이 BASE이다.
BASE는 아래와 같은 성질을 가지고 있다.
Basically Available : 기본적으로 가용하며
Soft-state : 사용자가 보관처리 하지 않으면, 데이터가 파기 될 수 있으며,
Eventually consistency : 당장은 아니지만 언젠가는 일관성이 유지되는 것

즉 핵심은 Eventually Consistency 로서 ACID 기반의 Transaction 이 아닌 BASE 기반의 Transaction을  처리하도록 하고 있다
이런 Eventually Consistency 를 유지하기 위한 방법으로 2가지가 있다.

Try Again Later

첫 번째 방법은 2개의 DB에 업데이트를 하는 경우 첫 번째 DB입력이 성공하고 2번째 입력이 실패하더라도 전체적으로 서비스 수행으로 진행되는 것으로 본다. 2번째 DB에 입력 로직은 별도의 로그 파일이나 로그 DB를 통해 그 정보를 보관하고 있고, 추후에 그 데이터 입력을 재시도 하도록 한다.

Abort the Entire Operation
또 다른 방법은 오류 시 전체 작업 취소이다. 첫 번째 데이터 입력이 성공한 후, 두 번째 서비스를 통한 처리 작업 오류 시 첫 번째 입력 상태를 원복시키는 것이다. Compensating transaction이라고도 하며, 이전 상태로 돌아가기 위해 DB의 rollback 명령을 수행하는 게 아니라 보상로그 테이블 등을 참조하여 DELETE 문을 직접 수행해서 원상태로 돌아가는 것이다.
사실 이러한 DELETE 작업이나 원래 상태로 돌아가는 것 조차도 실패할 수 있기 때문에 compensating log 파일이나 테이블을 통해 재시도를 해야 한다

위의 2가지 방법 모두 서비스 단에서 일일이 개발자에게 맡겨서 개발하게 한다면 MSA 서비스 구축을 성공할 수 없다. 따라서 해당  분산환경 Transaction을 구현하기 위해서는 Transaction 로그 History 기반에 자동으로 Transaction 관리를 할 수 있는 MSA 환경 지원을 위한 framework 구축이 필요하다

이상 좋은 서비스 구축을 위한 기본 서비스 분리를 위한 방안 및 Transaction 처리 방안을 간단히 정리해 보았다.  다음 시간은 이러한 서비스를 어떠한 Host 환경에서 그리고 어떠한 규모단위로 분리하여 구축하면 좋을 지 설명하도록 하겠다.


참조문서

Sam Newman, Buildimg Microservices, Oreilly 2015

Eric Evans, Domain-Driven Design, Addison-Wesley Professional, 2003

https://en.wikipedia.org/wiki/ACID

https://en.wikipedia.org/wiki/Eventual_consistency




New Multi-Channel Dynamic CMS

Micro Service Architecuture 의 중심 API Server

2010년 이후 급격하게 보급된 스마트폰으로 인해 브라우저를 통한 웹서비스 외에도 모바일 앱를 함께 고려한 멀티 채티 서비스를 필수적으로 고민해야 되는 시기가 왔다.
어떠한 서비스는 웹보다는 앱이 메인이 되는 서비스도 많이 늘어났지만 , 일반적인 기업환경에서 웹서비스를 메인으로 고객을 위한 디바이스 채널이 점점 늘리는 추세이며, 그에 따라 개발 비용 증가 및 빠른 서비스 출시에 대한 압박이 심해지고 있다.

 다양한 플랫폼을 준비해야 되는 상황에서 어떻게 보다 빠르게 서비스를 출시하고 개발하기 위해 필수적인 MSA(Micro Service Architecture) 및 그 중심인 API Server에 대해 알아보도록 하겠다.

Monolithic Architecture

일반적인 서버 사이드 기업용 web application 은 Java 인 경우는 WAR(Web Application ARchive) 형태와 같은 모놀리틱 아키텍처를 가지고 있다. 
모놀리틱 아키텍처는 단일 디렉토리 구조에 모든 데이터 억세스부터 controller , 화면 관련 UI 및 각종 library 까지 하나의 단일 디렉토리 구조에 모두 모아놓고 배포하는 방식이다.
아래 그림과 같이 하나의 배포판에 모든 UI 및 controller , 그리고 각종 Business Logic 이 하나로 묶여서 관리, 배포되는 방식이다. 상황에 따라 유지보수나 사이트를 관리하면서 각 기능별로 별도로 개발, 배포하고 있지만, 근본적인 형태는 아래와 같다.
[기본 모놀리틱 아키텍처 구조]


초창기 WAR 크기나 규모는 지금처럼 크지 않았지만 현재 대부분은 웹서비스는 그 규모가 상당히 크기때문에 WAR 단위로 배포하고 관리하기는 힘들어지는 단점을 가지고 있다.

초기 모놀리틱 아키텍처의 장점은 다음과 같았다.

  • 개발 편의성 : IDE툴이 모놀리틱 아키텍처 개발방식에 최적화 되어있다.
  • 배포 단순함 : 손쉽게 WAR 형태로 배포할 수 있다.
  • 확장성 : 다수의 WAR 형태를 이용해서 손쉽게 시스템을 확장할 수 있다.
현재 위의 3가지 장점을 동의하는 개발자나 TA 는 거의 없을 것 같다. 왜냐하면 예전처럼 웹 서비스 개발 규모가 단순하지 않고 고려해야 될 사항이 많기 때문이다.  현재 웹 어플리케이션  규모가 엄청나게 커져서 개발,배포,확장성 모두 불편해지고 있는 상황이며 아래와 같은 단점을 가지는 아키텍처 구조가 되어 버렸다.

  • 웹 어플리케이션 이해를 어렵게 만들고, 수정도 어려워 진다. 모듈화는 시간이 갈수록 의미가 없어지며, 소스 품질도 점점 낮아진다.
  • IDE 개발의 어려움 : 한번 WAS에 올라가는 프로그램 양이 커지고 무거워 져서 테스트도 힘들고 종속성이 강해지며 디버그도 힘들어진다.
  • 배포 문제점 : 작은 단위로 배포할 수 있겠지만 이것은 원래 WAR의 취지가 아니다. 콤포넌트가 변경되면 그 콤포넌트에 연관된 배포도 함께 고려해야 되어야 한다.
  • 작업분배의 어려움 : 일반적으로 메뉴 단위로 할 수 밖에 없는데, 어느 부분까지 공통영역이고 어느 부분까지 별도의 개발영역인지 애매할 때가 많다.


새로운 대안 Micro Service Architecture

기존의 무겁고 변경이 힘든 아키텍처 구조에서 새롭게 대안이 되고 있는 방식은 마이크로 서비스 아키텍처 구조이다.
각각의 작은 서비스 단위로 분할하고 각 서비스가 기존에 영향을 받지 않고 개발/배포를 가능하도록 하기 위한 아키텍처 구조로 아직 명확하게 정답이 있는 상황은 아니지만,기존의 모놀리틱 아키텍처 문제점을 상당부분 해결해 줄 수 있는 기대를 한 몸에 받고 있는 아키텍처이다.

[Micro Service Architecture]


MSA 는 다음과 같은 특징을 가지고 있습니다.

  • small & focus: 각 기능들은 작게 설계되고 한가지 일을 잘하는데 집중
  • API : 각각의 서비스는 API를 통해 통신
  • autonomous : 자율적으로 서로 영향을 최소화

MSA 의 핵심  API  Server

Micro Service Architecture가 가능하도록 하는 핵심 기술에는 API 서비스가 있다. 가장 기본적으로 UI 및 비즈니스 로직을 분리해야 하는데 현재로는 API Server(Gateway)를 통해 분리시키는 것이 가장 이상적인 방법이 때문이다.
모놀리틱 아키텍처 구조에서는 특정 서버에 있는 비즈니스 로직을 이용하고 싶어도 기술적으로 풀어야 할 문제들이 상당히 많기 때문에 실제 프로젝트에서는 중복적인 난개발이 이루어지는 경우가 상당히 많다.

[API Server 아키텍처]

위 그림에서와 같이 기업내부의 database 및 EAI 서버와 같이 각종 데이터 이용에 대한 부분을 API Server 를 통해 통제하고 관리하도록 하며, 그 데이터 이용을 REST 나 다양한 web protocol 을 통해 모바일앱이나 웹에서 손쉽게 사용할 수 있도록 하는데 특징이 있다. 

API 서비스 중심으로 아키텍처가 개편되면 비즈니스 재활용성도 높이며 그 로직을 활용하는 UI도 업무 기술 종속성을 탈피하여 서비스 개발 및 배포의 생산성을 극대화 할 수 있습니다.

API 서비스를 말하면 보통 OPEN API 기반의 공개용 API 서비스르 생각하기 쉽지만, Google,Netflix나 Amazon 과 같은 회사들은 이미 기업 내부의 업무로직을 API 로 정의하고 각 웹서비스나 앱에서는 그 API 를 호출해서 사용하는 방식을 취하고 있다.
가장 유명한 일화는 2002년 Amazon CEO Jeff Bezos가 내부 역량강화를 위해 내부 개발자에게 API 개발 강령을 정의하고 강제화 하도록 하였다.

  • All teams will henceforth expose their data and functionality through service interfaces.
  • Teams must communicate with each other through these interfaces.
  • There will be no other form of inter-process communication allowed: no direct linking, no direct reads of another team’s data store, no shared-memory model, no back-doors whatsoever. The only communication allowed is via service interface calls over the network.
  • It doesn’t matter what technology they use.
  • All service interfaces, without exception, must be designed from the ground up to be externalizable. That is to say, the team must plan and design to be able to expose the interface to developers in the outside world. No exceptions.


API Server의 역활
기업환경에서 API 서버는 다음과 같은 역활을 할 수 있다.

통합 개발 환경
 - 새로운 서비스나 프로그램 개발시 처음부터 모놀리틱 방식으로 모든것을 구축 할 필요없이 필요한 업무로직 개발 및 이용에 집중할 수 있다.

모바일 앱 Backend service
 - iOS및 안드로이드 뿐만 아니라 각종 디바이스용 앱을 개발할때마다 별도의 backend service 를 구축할 필요 없이 API Server를 통해 Mobile backend server를 손쉽게 구축할 수 있다. 앱뿐만 아니라 기타 다양한 어플리케이션에서 바로 이용이 가능하다.

Business Logic 관리

 - 업무로직을 업데이트하고 변경할때마다 어떻게 분산되고 이용되지는 기존 모놀리틱 아키텍처에서는 파악하기 힘들다. API  Server를 통한 중앙 통제는  기존 로직을 그대로 이용하면서 버전업을 하거나 병행처리가 가능하기 때문에 생산성 향상 및 개발 안정성이 증대된다.


참고문서



New Multi-Channel Dynamic CMS