블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

분산 로그 수집기 Fluentd 소개


조대협 (http://bcho.tistory.com)



요즘 들어 빅데이타 분석 관련 기술들을 보다보니, 역시나 여러 데이타 소스에서 데이타를 수집해 오는 부분이 여러 데이타 소스를 커버해야 하고, 분산된 여러 서버에서 데이타를 수집해야 하는 만큼 수집 컴포넌트의 중요성이 점점 더 올라가는 것 같다.

그래서 요즘 빅데이타를 위한 데이타(및 로그) 수집 플랫폼을 보고 있는데, 예전 Flume 등 여러 로그 수집 솔루션이 있었는 것에 비해서 조금 정리된 느낌이라고나 할까?  Scribed, Fluentd 그리고 ELK (Elastic Search + Logstash + Kibana 조합)에서 사용되는 Logstash등이 있는데, 대부분 Fluentd와 Logstash로 수렴 되는 것 같다. 양쪽 모두 오픈소스이고 별도의 엔터프라이즈 라이센스 정책을 가지고 있다.

Logstash는 아키텍쳐 적응에 대한 유연성과 연동 솔루션에 대한 호환성을 강조하고 있기 때문에 타 솔루션과 연동이 강하고 반면, Fluentd는 아키텍쳐의 단순성과 이를 기반으로 한 안정성을 초점을 두고 있다. 그래서 아키텍쳐 구성이나 설정이 간단하다.


이 글에서는 Fluentd에 대한 간략한 개념과 사용 방법에 대해서 알아보도록 하겠다.

Fluentd를 이용한 로그 수집 아키텍쳐

Fluentd를 이용한 로그 수집 아키텍쳐를 살펴보면 다음과 같다.

아래 그림과 같이 각 서버에, Fluentd를 설치하면, 서버에서 기동되고 있는 서버(또는 애플리케이션)에서 로그를 수집해서 중앙 로그 저장소 (Log Store)로 전송 하는 방식이다.




위의 그림은 가장 기본적인 구조로 Fluentd가 로그 수집 에이전트 역할만을 하는 구조인데, 이에 더해서 다음과 같이 각 서버에서 Fluentd에서 수집한 로그를 다른 Fluentd로 보내서 이 Fluentd가 최종적으로 로그 저장소에 저장하도록 할 수 도 있다.


중간에 fluentd를 넣는 이유는, 이 fluentd가 앞에서 들어오는 로그들을 수집해서 로그 저장소에 넣기 전에 로그 트래픽을 Throttling (속도 조절)을 해서 로그 저장소의 용량에 맞게 트래픽을 조정을 할 수 있다.

또는 다음 그림과 같이 로그를 여러개의 저장소에 복제해서 저장하거나 로그의 종류에 따라서 각각 다른 로그 저장소로 라우팅이 가능하다.


Fluentd 내부 구조

Fluentd를 이용해서 로그 수집 아키텍쳐를 구성하는 방법을 대략적으로 알아보았는데, 그렇다면 Fluentd 자체의 구조는 어떻게 되어 있을까?

Fluentd는 크게 다음 그림과 같이 Input,Parser,Engine,Filter,Buffer,Ouput,Formatter 7개의 컴포넌트로 구성이 된다.  7개의 컴포넌트중 Engine을 제외한 나머지 6개는 플러그인 형태로 제공이 되서 사용자가 설정이 가능하다.

일반적인 데이타 흐름은 Input → Engine → Output 의 흐름으로 이루어 지고,  Parser, Buffer, Filter, Formatter 등은 설정에 따라서 선택적으로 추가 또는 삭제할 수 있다.



Input

Input은 로그를 수집하는 플러그인으로, 다양한 로그 소스를 지원한다. HTTP, tail, TCP 등 기본 플러그인 이외에도, 확장 플러그인을 통해서 다양한 서버나 애플리케이션으로 부터 다양한 포맷의 데이타를 수집할 수 있도록 해준다.

Parser (Optional)

Input 플러그인을 통해서 데이타를 읽어도 데이타 포맷이 Fluentd에서 지원하지 않는 데이타 포맷인 경우가 있기 때문에, 이 데이타를 파싱 하기 위해서, Parser 플러그인을 선택적으로 사용할 수 있다. Regular expression  기반으로 스트링을 Parsing 하는 플러그인 뿐 아니라, apache, nginx, syslog등 다양한 포맷의 데이타를 파싱할 수 있는 플러그인을 제공한다.

Filter (Optional)

Filter 플러그인을 읽어드린 데이타를 output으로 보내기 전에, 다음과 같은 3가지 기능을 한다.

  • 필터링

  • 데이타 필드 추가

  • 데이타 필드 삭제 또는 특정 필드 마스킹

필터링은 특정 데이타만 output 필드로 보내고, 나머지는 버리도록 한다. 예를 들어 로그 데이타에 “seoul”이라는 문자열이 있을 경우만 로그 서버로 보내거나 “error”, “warning”과 같은 특정 패턴이 있을 경우에만 로그 저장소로 보내도록할 수 있다.


데이타 필드 추가는 기존 들어온 로그 데이타에 데이타를 전송한 서버명 (Host명)등을 추가해서 로그 저장소로 보낼 수 있다.

마지막으로 데이타 필드 삭제는 불필요한 필드를 삭제하거나 개인 정보등 민감 정보를 삭제하거나 해쉬화하여 데이타 저장소로 보낼 수 있는 기능을 한다.

Output

Output은 Input 플러그인과 반대로, 앞에서 필터링된 데이타를  데이타 저장소 솔루션에 데이타를 저장하도록 한다. (mongodb나 AWS S3 , Google의 Big query등)

Formatter (Optional)

Output 플러그인을 통해서 데이타를 저장소에 쓸 때, Formatter 를 이용하면 쓰는 데이타의 포맷을 정의할 수 있다.(cf. Input의 parser가 포맷에 맞게 읽는 플러그인이라면, Formatter는 Output을 위한 포맷을 지정하는 플러그인이라고 보면 된다.)

Buffer (Optional)

Input에서 들어온 데이타를 바로 Output으로 보내서 쓰는것이 아니라 중간에 선택적으로 Buffer를 둬서 Throttling을 할 수 있다. 버퍼는 File과  Memory 두가지를 사용할 수 있다.

간단하게 구조와 작동 원리를 보면 다음과 같다.



<그림. fluentd의 로그 writing 흐름>

원본  http://docs.fluentd.org/articles/buffer-plugin-overview


버퍼에는 로그데이타를 분리하는 tag 단위로 chunk가 생성이 된다.

chunk는 태그별 큐라고 보면 된다. 예를 들어 error, info, warning, user 와 같이 태그를 분리하면 error 로그는 error chunk에 저장이 되고, info 로그는 info chunk에 저장된다.

Chunk에 데이타가 쌓여서 buffer_chunk_limit 만큼 chunk가 쌓여서 full이 되거나, 또는 설정값에 정의된 flush_interval 주기가 되면 로그 저장소로 로그를 쓰기 위해서 Queue에 전달이 된다.


<그림. Memory buffer 설정 예제>

참고 : http://docs.fluentd.org/articles/buffer-plugin-overview


다음 Queue에서는 데이타를 읽어서 로그 저장소에 데이타를 쓰는데, 로그 저장소에 문제가 없다면 바로 로그가 써지겠지만, 네트워크 에러나 로그 저장소 에러로 로그를 쓰지 못할때는 retry_wait 시간 만큼 대기를 한 후에, 다시 쓰기를 시도한다. 다시 쓰기를 실패하면 전에 기다린 시간의 2배 만큼, 또 실패하면 또 2배만큼을 기다린다. (1초, 2초, 4초,8초…) 다시 쓰기 시도는 설정값에 지정된 retry_limit 횟수까지 계속 진행한다.

만약에 Queue 가 차버렸을때 처리에 대한 정책을 설정할 수 있는데, “exception”과, “block” 모드 두가지고 있고, exception 모드일 경우에는 BufferQueueLimitError 를 내도록 하고, block 모드의 경우에는 BufferQueueLimitError가 해결될때 까지, input plugin을 중지 시킨다 (더이상 로그를 수집하지 않는다는 이야기).

Queue가 차버렸을때 다른 처리 방법으로는 큐가 다 찾을때, Sencondary output을 지정해서, 다른 로그 저장소에 로그를 저장하는 방법이 있다. 예를 들어 로그를 mongodb에 저장하도록 했는데, mongodb 나 네트워크 장애로 로그를 쓸 수 없는 경우에는 secondary output을 AWS S3로 지정해놓고, S3로 로그를 일단 저장하게 하고 나중에 mongodb가 복구된 후에, S3에서 다시 mongodb로 로그를 수집하는 방식을 취할 수 있다.



<그림. Secondary output 설정 예제>

출처 : http://docs.fluentd.org/articles/buffer-plugin-overview


Buffer 플러그인과, 에러 처리에 대한 자세한 내용은 http://docs.fluentd.org/articles/buffer-plugin-overview 를 참고하기 바란다.


데이타 구조

다음으로 Fluentd가 내부적으로 어떻게 로그 데이타를 핸들링 하는지 데이타 구조를 살펴보면 다음과 같다.



출처 :http://pt.slideshare.net/frsyuki/fluentd-set-up-once-collect-more


데이타는 크게 3가지 파트로 구성된다. Time, tag, record

  • Time : 로그데이타의 생성 시간

  • Record : 로그 데이타의 내용으로 JSON형태로 정의된다.

  • Tag : 이게 가장 중요한데, 데이타의 분류이다. 각 로그 레코드는 tag를 통해서 로그의 종류가 정해지는데, 이 tag에 따라서 로그에 대한 필터링,라우팅과 같은 플러그인이 적용 된다.

간단한 테스트

테스트 환경은 맥북을 기준으로 하였다.

http://docs.fluentd.org/articles/install-by-dmg 를 따라서 테스트를 하면 되는데, 먼저 fluentd를 받아서 인스톨을 한다.

인스톨이 끝나면, fluentd 프로세스인 td-agent는 /opt/td-agent/usr/sbin/에 인스톨이 된다.

그리고 디폴트 설정 파일은 /etc/td-agent/td-agent.conf에 저장된다.

td-agent.conf의 내용을 보면 다음과 같다.



<ROOT>

 <match td.*.*>

   type tdlog

   apikey xxxxxx

   auto_create_table

   buffer_type file

   buffer_path /var/log/td-agent/buffer/td

   <secondary>

     type file

     path /var/log/td-agent/failed_records

     buffer_path /var/log/td-agent/failed_records.*

   </secondary>

 </match>

 <match debug.**>

   type stdout

 </match>

 <source>

   type forward

 </source>

 <source>

   type http

   port 8888

 </source>

 <source>

   type debug_agent

   bind 127.0.0.1

   port 24230

 </source>

</ROOT>



<source> 부분을 보면 type이 http, port가 8888인 정의가 있다. 이 정의는 http://localhost:8888 로 부터 로그를 수집하겠다는 정의이다.

다음 <match>부분을 보면 <match debug.**> 라는 정의로 태그가 debug.**  로 정의된 로그에 대해서 type stdout으로, stdout (화면)으로 바로 출력하겠다는 정의이다.

http://localhost:8888/{debug.**} 로 들어오는 요청에 대해서 stdout으로 로그를 출력하겠다는 설정이다.


설정 파일을 확인했으면, 이제 기동을 해보자

/opt/td-agent/usr/sbin 디렉토리에서 -c 옵션으로 설정 파일을 지정하고 td-agent를 다음과 같이 실행해보자

% ./td-agent -c /etc/td-agent/td-agent.conf


에이전트가 실행되었으면 curl 명령을 이용하여 http://localhost:8888/debug.test 로 {"json":"message"} 로그 문자열을 전송해보자

% curl -X POST -d 'json={"json":"message"}' http://localhost:8888/debug.test


다음은 실행 결과 이다.





다음과 같이 td-agent가 기동된 후에,  맨 아랫줄에 debug.test 라는 태그 이름으로 {“json”:”message”}라는 로그가 수집되어 출력된것을 볼 수 있다.

데몬으로 실행하기

앞에서는 CLI상에서 foreground로 실행을 하였는데, 맥에서 서비스로 백그라운드 작업으로 실행을 할 수 있다. 실행 방법은

%sudo launchctl load /Library/LaunchDaemons/td-agent.plist

를 실행하면 백그라운드로 실행된다. 백그라운드로 실행을 위한 스크립트인 td-agent.plist는 fluentd설치시  /Library/LaunchDaemons/td-agent.plist에 자동 생성된다.

백그라운드 작업이기 때문에, stdout이 없고 stdout으로 출력되는 로그는 /var/log/td-agent/td-agent.log로 확인할 수 있다.





실행중인 프로세스를 종료 하는 방법은

%sudo launchctl unload /Library/LaunchDaemons/td-agent.plist

를 사용하면 된다.


다음 글에는 실제로 fluentd 를 설정해서 Google의 Bigquery또는 큐로 로그를 전달하는 설정 방법에 대해서 알아보겠다.



저작자 표시 비영리
신고

REST API의 이해와 설계

아키텍쳐 /대용량 아키텍쳐 | 2016.04.05 22:33 | Posted by 조대협

REST API 이해와 설계


조대협 (http://bcho.tistory.com)


REST API에 대한 이해와 디자인 방법 그리고 보안방법에 대해서 설명합니다.




대용량 아키텍쳐와 성능 튜닝 책의 4장을 정리한 내용인데, 강의나 스터디등에 자유롭게 사용하셔도 됩니다.  (출처 명기 필요)




저작자 표시 비영리
신고

MSA의 중복 개발에 대한 단상


조대협 (http://bcho.tistory.com)


어제 우연한 기회로, API Academy 세미나에 다녀왔습니다.

발표자는 Mike Amundsen  이라는 분으로, CA의 API 아카데미의 일원이며, OReilly 출판사를 통해서 REST API에 대한 저서를 집필한 분이기도 합니다.

http://www.oreilly.com/pub/au/1192





API 아카데미였지만, 결국 MSA와 조직 문화 소통으로 수렴되는 내용이었습니다만, MSA 에 관련하여 재미있는 접근이 있어서 남겨놓고자 합니다.


예로 든것중의 하나가 API를 외부용, 내부용, 그리고 특정한 파트너용 3가지로 나누어서 접근을 하였는데, 이 접근 방식보다 특이했던 것이 구현의 주체입니다.


일반적인 생각으로는 유사한 API라면, API를 만들어놓고, 차이가 나는 부분만 Mediation을 통해서 재 사용하는 개념을 접근하였습니다.


예를 들어 GET /users/{userid} 라는 API가 있을때, 이 API를 내부용으로 만들어놓고, 이 API를 wrapping해서, 추가 인증/인가 기능을 추가하여 외부용, 파트너용으로 제공하는 방법이 일반적인 방식인데,


Amunsen 은 다른 접근 방법을 제시했습니다. "외부용,내부용,파트너용 API를 각각의 팀이 따로 만든다"

였습니다. 데이타가 같으니 일관성은 보장이 될터이고, 각 팀으로 서비스를 나눠서 각팀이 각각의 API를 만들게 되면, 기동성이 늘어나고, 고객의 요구 사항이 각각 다르니 거기에 기민하게 대응할 수 있다는 논리입니다.


중복 개발이나, 종속성에 대한 문제가 발생할 수 는 있겠지만, 오히려 이게 맞는 접근 방법이 아닌가도 싶습니다.

MSA의 근본적인 목적은 작은 서비스로 나눠서 개발의 기민성을 확보하고, 고객의 요구 사항을 빠르게 반영하는데 있는데, 공통 API를 재사용하게 되면, 재 사용성 자체는 올라갈지 모르겠지만, 반대로 의존성때문에 전체 프로젝트 일정에 문제가 생길 수 있습니다.


같은 논리로, 웹,모바일 백앤드가 있을때, 팀의 크기가 크다면, 공통 API 시스템을 쓸것이 아니라, 각자 API 백앤드 시스템을 만들어서 기민성을 확보하는 것도 하나의 예가 되겠습니다.


중복 개발과 낭비는 있겠지만, 기민성 확보와 각각의 팀이 컨택스트와 도메인을 완전하게 이해할 수 있다는 점에서, 이 방식도 충분히 고려해볼만한 가치가 있지 않을까 합니다.

저작자 표시 비영리
신고

 

트위터 모바일 SDK 서비스 패브릭에 대한 소개


조대협 (http://bcho.tistory.com)




트위터에서는 2014년 부터, 모바일 생태계 지원을 위해서 다양한 기능을 제공하는 Fabric 서비스를 제공하고 있다. 데이타 분석 및 리포팅, 트위터 연동등 다양한 기능을 제공하고 있는데, 대략적인 프로덕트들에 대한 기능과 특징을 살펴보고자 한다.



Crashlytics - Crash Reporting (https://fabric.io/kits/android/crashlytics)


모바일앱에 대한 크래쉬 내용에 대한 수집 및 분석 기능을 제공한다.  

특이한 사항으로는 크래쉬 분석 뿐만 아니라, 베타 사용자나 테스터들에게 앱을 배포할 수 있는 기능을 제공하고 베타 테스트 사항을 추적할 수 있는 기능을 제공한다.

근래에는 게임 개발 SDK인 Unity를 지원하는 기능이 추가 되었다.

 


Answers - Mobile Analytics Kit (https://fabric.io/kits/android/answers/summary) 


Google Analytics나 Yahoo의 Flurry와 비슷한 앱 모니터링/리포팅 서비스이다. Google Analytics와는 다르게 완전 무료이다. (데이타 Limit가 없다.)

단 타 서비스와 차이점은 복잡한 형태의 분석이 불가능하다 Cohort, Funnel 분석이나 User Path등 복잡한 분석은 불가하고 DAU,MAU,Session등 단순한 분석만 가능하다.


단순하기 때문에 지표 이해가 쉬운것이 장점으로 볼 수 있고, 또 다른 장점은 타 서비스에 비해서 리얼타임이라는 것이다. 대쉬보드의 수치는 20~30초 정도의 지연이 있는 수치로, 실시간 이벤트를 하거나 PUSH에 대한 반응을 바로바로 봐야할때나 TV CF후에 반응등 실시간 반응 분석이 필요할때 유용하게 사용할 수 있다.


정확한 분석을 위해서는 Fabric 하나로만은 불가능하겠지만 실시간성을 지원하는 점을 보면, Fabric + Flurry와 같이 두개의 솔루션을 조합해서 사용하는 것을 고려하는 것이 좋다.


Answers에서 특이한 기능중에 하나는, 트위터의 사용자 정보를 기반으로, Fabric Answer 를 통해서 모니터링 되는 사용자에 대한 특성 파악이 가능하다는 것이다. 트위터는 컨텐츠 및 여러가지 종류의 계정 (스포츠, 코메디 등등)을 운영하고 있기 때문에, 트위터는 트위터 사용자의 특성이 어떤지를 알 수 있고, 이 정보를 바탕으로 Fabric이 연동된 서비스의 각 사용자들의 특성을 파악해줄 수 있기 때문에, 서비스 운영 입장에서 사용자에 대한 인사이트를 제공할 수 있다. 




Digit Kit


Digit Kit는 SMS를 이용한 인증 서비스 이다. SMS를 통해서 인증 번호를 전송해서 본인 여부를 확인하는 서비스인데, 200여개의 국가를 지원하고 있고, 가장 중요한건 무료다!!. 글로벌 서비스를 제공 하는 경우 글로벌 SMS 서비스를 고려해야 하고, 또 그에 대한 금액도 만만하지 않은데, 하나의 서비스로 글로벌 커버를 비용 부담없이 제공하는 것은 활용을 고려해볼만하다고 보다. 향후  Email Verification 서비스도 함께 제공할 예정이다. 




Twitter Kit


Twitter Kit은 트위터 기능을 사용하기 위한 모바일 SDK이다. 특이한 점은 트위터로의 공유하는 GUI등을 SDK로 제공해서 어렵지 않게 트위터로의 공유 기능을 구현할 수 가 있다. 




Curator - Twitter contents curation service


트위터 컨텐츠를 모아서 큐레이션 (기존의 컨텐츠들을 2차 가공하여 새로운 컨텐츠를 만드는 것) 해주는 서비스로, 주로 미디어 서비스나 컨텐츠 공급자, 큐레이터에게 유리한 서비스로 Curator라는 저작툴을 이용하여, 큐레이션할 컨텐츠를 골라서 특정 주제에 해당하는 피드를 만들 수 있다. 아래는 서울의 첫눈이라는 주제로 트윗을 검색한 후에, 이를 골라서 콜랙션을 만드는 저작도구 화면이다. 



다음은 큐레이트된 컨텐츠를 임베딩하기 위해서 퍼블리슁 화면이다. 



저작자 표시 비영리
신고

쉽게 이해하는 모바일 데이타 분석



조대협(http://bcho.tistory.com)


모바일 서비스 비지니스를 진행함에 있어서 가장 중요한 것중 하나는 지표에 따른 의사 결정과 서비스 개선이다. 이를 위해서, 어떤 지표들이 필요한지 정의하고 어떻게 측정할지에 대한 정확한 이해가 필요한데, 이 글에서는 모바일 서비스 리포팅에 대해 어떤 지표가 있고 어떻게 활용해야 하는지, 그리고 이런 지표를 수집 분석하기 위한 도구들에 대해서 설명하도록 한다.


모바일 서비스에서 단계별 사용자 흐름


먼저 지표를 이해하기 전에, 사용자가 모바일 서비스 가입부터 사용에서 부터 이익을 내줄때 까지 어떤 흐름을 거치는지에 대해서 살펴볼 필요가 있다. 여러 글들이나 서비스들에서 다소 용어 차이는 있지만 대부분 아래와 같이 단계를 정의한다. 





Acquisitions (사용자 획득 단계)


“사용자 획득 단계”는, 사용자가 앱을 설치 하는 단계로 광고/마케팅등을 통해서 사용자가 앱을 인지하고 설치하는 단계인데, 조금 더 세분화 하면, 설치 후 첫번째 실행을 한 단계로 정의하거나 또는 설치 후 회원 가입까지 한 단계를 “사용자가 획득 되었다” 라고 판단할 수 있다.


사용자의 유입은 검색엔지이나 앱스토어의 검색등을 통하거나, TV,온라인 캠페인(인터넷 광고), 오프라인 캠페인등을 통해서 이끌 수 있다. 유입 경로가 다양하기 때문에 모든 경로에 대한 추적은 불가능하지만, 특히 온라인 캠페인(인터넷 광고) (페이스북이나 카톡 등)는 손쉽게 추적이 가능하고 사용자 획득양에 따라서 광고 플랜을 조절할 수 있기 때문에, 이러한 온라인 캠페인은 시작하기 전에 사용자 유입이 비용대비 어떻게 효과가 있는지를 측정할 수 있는 준비 (분석툴등)를 해놓고 시작해야 한다.


Retention (사용자 유지 단계)


마케팅등을 통해서 사용자를 유입시켰으면 이 유입된 사용자를 서비스에 잡아놓아야 하는데, 이를 Retention, 즉 사용자 유지라고 한다. 이 사용자 유지율을 가입한 사용자가 가입한 이후, 얼마나 꾸준히 재 접속을 하는지를 통해서 측정하는 것이 일반적인데, 1일 후 재접속율, 2일..7일 재접속율을 체크하면 된다. 


이 단계에서 이탈을 방지하고 얼마나 사용자를 Lock in 하여 충성도가 높은 사용자층을 유지하는 것이 중요하다.


Engagement (사용자 활동 단계)


사용자가 서비스를 지속적으로 사용하기 시작하면, 서비스와 사용자간의 인터랙션 즉 활동이 시작되는 단계가 된다. 미디어 서비스일 경우 단방향으로 컨텐츠를 보기만 하는 단방향성의 활동보다는 댓글이나 좋아요 버튼등을 통한 양방향 활동등을 유도하여 서비스의 로열티를 높이고, 서비스에 체류하는 시간을 늘려서 장기적으로 수익화할 수 있는 원천으로 삼아야 한다.


Monetize (수익화 단계)


고정 사용자 층이 형성이 되었으면, 이 사용자 층을 이용하여 수익을 창출해야 하는 데, 광고나 게임의 경우 인앱 구매, 쇼핑의 경우 물품의 실제 구매 단계 까지 연결이 되서 최종적으로 수익을 창출하는 단계이다.


사용자의 인터랙션은 앞에서 설명한바와 같이 위의 그림 처럼 깔때기 형태로 이루어지며 최종 수익을 발생하는 사용자를 얼마나 많이 유도 하느냐가 비지니스의 성패가 된다. 


이러한 흐름을 설명하는 것은 보통 모바일 앱 데이타 분석에 있어서 상당히 많은 지표들이 있고, DAU,MAU,Session Time등 각각의 지표만을 모니터링 하고 분석할뿐 전체 지표가 어떻게 연결되는지 연관성에 대한 인사이트가 적은 것이 대부분의 문제라고 생각하기 때문에 사용자의 단계별 활동에 대한 흐름을 설명하였다.


단계별 지표 정의와 의미


이번에는 위에서 서술한 각 단계별로 모니터링 하는 주요 중요 지표에 대해서 알아보도록 하자



Acquisition 


Download

앱을 다운로드해서 설치한 횟수이다. 이때 중요한 것이 이 Download 수와 실제 사용자 수는 일치 하지 않는다는 것이다. 같은 사용자가 기기를 바꿔서 다시 다운로드할 수 도 있고, 여러기기에 다운로드를 할 수 도 있고 혹은 앱을 지웠다가 재 설치할 수 도 있기 때문에 , 다운로드 수와 사용자 수를 혼돈하지 않도록 한다. 이러한 다운로드 수는 별도의 솔루션을 사용하지 않더라도 구글 플레이 스토어나, 애플 앱스토어 등에서 쉽게 모니터링 할 수 있다.



New User

신규 사용자 수이다.  앱을 설치하고 첫번째로 사용하는 사용자의 수로, 실제로 프로모션등으로 인하여 앱을 설치는 하지만, 사용하지도 않고 삭제하는 경우의 수도 많기 때문에, 별도로 측정이 필요하다.


Demographic Info

그외, 사용자에 대한 기본적인 정보를 수집할 수 있는데, 나이, 성별,  지역적인 위치, 사용 단말의 종류, 통신사등 기본적인 인구 통계나 디바이스에 대한 정보를 수집을 통해서 주로 어떤 사용자 층이 서비스를 사용하는지 인지할 수 있다. 



Install tracking

사용자 획득 단계에서 중요한 지표중의 하나가, 이 사용자가 어디를 통해서 들어왔냐는 것이다. 온라인 마케팅을 통해서 들어온건지. 그렇다면 채널이 페이스북인지? 아니면 웹 사이트 광고인지, 어느 웹사이트 인지? 아니면 공유 기능등을 통한 추천으로 들어온것인지 이메일 마케팅을 통해서 앱 인스톨이 유도 된것인지등이 분석이 되어야 한다.

이러한 분석은 안드로이드 앱의 경우 캠페인 관리 기능을 통해서 UTM 정보라는 것을 획득하면, 어느 경로를 통해서 앱 인스톨이 유도 되었는지 추적이 가능하기 때문에, 결과적으로 어느 마케팅 채널을 통해서 사용자 유입이 활발하게 이루어지는지 판단이 가능하고 이를 통해서 효율적인 채널에 마케팅 리소스를 집중할 수 있도록 해준다.


Retension


Retension rate는 신규 사용자의 재 방문율 분석을 통해서 인지할 수 있다. 이런 수치는 Google Analytics나 Yahoo의 Flurry등읗 이용하여 분석이 가능한데, 아래 그림은 Flurry의 Retension 모니터링 화면이다. 


  


가입자가 가입을 한후에, 날짜가 지남에 따라 얼마나 많은 사람이 남아 있는 가를 볼 수 있다. 당연히 Day 0 에는 100% 일테고, 위의 그림을 보면, 1일 차에는 대략 60%의 사용자가 남게 되고, 그후에 40~50% 사용자가 유지되는 것을 볼 수 있다.


Engagement


Engagement 는 서비스에 대한 사용자의 활동량을 측정하는 수치로 서비스의 종류나 특성에 따라 측정해야 하는 수치가 다르다. 예를 들어 신문이나 방송같은 미디어 서비스의 경우 컨텐츠 뷰수가 중요할것이고, 게임같은 경우에는 플레이 시간이나, 레벨업 등이 중요할 것이고, 쇼핑의 경우에는 상품을 보는 수등이 중요할 수 있다.

이런 추가적인 지표는 각 서비스에 맞게 정의하는 것이 중요하지만, 공통적으로 사용할 수 있는 지표를 보면 다음과 같다


User Path

앱 상에서 사용자의 이동 경로로, 메인 화면으로 갔다가 각각의 메뉴로 사용자가 이동하고 각 메뉴별 체류 시간등을 분석해줌으로써 사용자가 주로 어떤 패턴으로 기능을 사용하는지 또한 어떤 기능이 많이 사용되고 안되는지 등에 대해서 분석이 가능하다.



 

Active User

Active User는 단위 시간동안 그 서비스를 사용한 사용자의 수를 뜻한다.

일반적으로 일단위나 주단위, 월단위를 많이 사용하는데 각각을  DAU(Daily Active User), WAU(Weekly Active User), MAU(Monthly Active User)라고 하고 앱의 서비스 규모를 측정하는 가장 일반적인 지표로 많이 사용된다. 


Session

다음으로 중요한 지표중 하나는 세션(Session)인데, 세션은 한명의 사용자가 한번 앱에 접속해서 사용하고 종료할때까지의 기간을 세션이라고 한다. 한명의 사용자가 하루에 여러번 앱을 사용하면 각각이 하나의 세션으로 취급되며, 일반적으로 안드로이드의 경우 하나의 세션을 사용자의 액션이 없을 경우 30분 후에 종료되는 형태로 정의된다. (cf. 웹에서 HTTP Session이 사용자 액션이 없으면 20분 후에 종료되는 것과 같은 종류로 보면 된다) 

이 세션의 수는 일반적으로 현재 앱을 사용하는 동시 접속자 수와 유사하다고 보면 된다. (사용자가 실제 사용을 종료하고도 30분 정도를 동시 사용자로 측정하기 때문에 다소 오차는 있지만, 전체적으로는 동접자 수와 유사하다고 판단한다.)

https://support.google.com/analytics/answer/2731565 는 Google Analytics에서 사용하는 세션의 개념이다.


Session Lenth

한번 접속했을때 사용자가 앱을 사용하는 시간을  Session Length라고 한다. 이 Session Length가 길다는 것은 그만큼 앱을 사용하는 시간이 길다는 의미로 사용자의 활동이 많다고 볼 수 있으나, 앱의 특성에 따라서 Session Length가 가지는 의미는 다르다. 알람 앱같은 경우에는 설정이나 알람이 울릴때만 앱이 사용되기 때문에, Session Length가 길 수 가 없고 짧다. 그래서 Session Length가 긴것 보다는 총  Session의 수가 얼마나 되느냐가 중요한 척도가 된다. 



Viral

근래에 모바일 서비스에서 중요한 지표중의 하나가 바이럴 지표인데, 페이스북과 같은 SNS 서비스를 통해서 공유가 되고, 이 공유를 통해서 들어오는 사용자 유입은 매우 중요하다. 그래서 추가적으로 SNS 매체별 공유 카운트 등을 별도로 추적할 필요가 있다.


Bounce rate

흔히들 놓치는 수치 중에 하나가 이탈율이다. 사용자 Install이 증가함에도 불구하고, 지속적으로 DAU가 늘어나지 않는 이유는 흔히 앱을 설치했다가 삭제하는 이탈 사용자 때문인데, 이러한 이탈율은 Google play store 등에서 쉽게 추적이 가능하다.


<그림. 구글 플레이스토어에서 일일 Uninstall 사용자 추적 예제> 


Loyalty (하루에 몇번 앱을 사용하는가?)

다음으로는 사용자의 충성도를 측정하는 지표인데, 주로 하루에 또는 일주일에 몇번 앱을 사용하는지를 측정한다. 



추가적으로 고민해야 하는 사항들


앞에서 모바일 앱 데이타 분석에서 일반적으로 살펴봐야 하는 지표들에 대해서 알아보았다. 이런 일반 지표 이외에 추가적으로 고려해야 하는 부분은 무엇이 있을까?


코호트  분석 (Cohort analysis)


코호트 분석이란, 분석 결과를 특정 사용자 그룹으로 (나이 또는 성별 등) 나눠서 더 깊게 분석하는 것으로, 집단의 특성에 따른 인사이트를 얻어서 서비스에 반영할 수 있다.

예를 들어서 DAU가 100만으로 꾸준히 유지 되는 서비스가 있다고 가정할때, 이를 연령 층으로 나누었을때 20대 사용자가 증가하고 30대가 감소한다면, DAU 향상을 위해서 30대를 위한 서비스 개선을 생각하거나 또는 서비스의 방향을 20대로 아예 바꿔 버릴 수 도 있다. 앞의 지표를 하나의 숫자로만 보고 분석하면 집단별 특성을 놓칠 수 있지만, 코호트 분석을 통하면 서비스를 사용하는 집단의 특성에 따라 다양한 해석이 가능하기 때문에 그에 따른 다양한 대응역시 가능하게 된다.


퓨넬 분석 (Funnel analysis)


Funnel / 깔때기 분석이라고 하는데, 특정 목표를 달성할때 까지 사용자의 잔존 비율을 단계별로 분석하는 분석 방법이다. 

앞에서 설명한 Acquisitions > Retain > Engagement > Monetization 의 단계도 뒤로 갈수록 사용자가 점점 낮아지는 깔때기 형태로 일종의 퓨넬 분석에 속한다.





위의 그림은 Flurry에서 제공하는 Funnel 분석 결과 화면으로, 자동차를 판매하는 사이트에서, 각 단계별로 넘어가는 사용자 통계로, Choose Car 단계에서 Check In 단계로 넘어갈때, 43.1 %의 사용자만 넘어간것을 볼 수 있다. 다음 단계는 각각 56.4%, 72.6%로 View State 목표를 달성하는 과정중에 사용자가 Check In 단계에서 가장 많이 이탈함을 알 수 있고 이 부분을 우선 개선해야 하는 것을 알 수 있다. 


이러한 퓨넬 분석을 이용하면, 사용자가 최종 목표에 다다르기 까지 어느단계에서 이탈을 하는지 쉽게 판단이 가능하고, 그 단계를 보강함으로써 최종단까지 사용자를 유도하도록 서비스를 개선할 수 있다.

 

지표의 단순화


지금까지 다양한 지표를 살펴봤는데, 비단 모바일 데이타 분석 뿐 아니라 일반적인 데이타 분석에서도 경험상 보면 필요한 핵심 지표의 수는 그리 많지 않다. 오히려 지표가 많을 수 록 혼란이 생기고, 각 지표의 의미를 이해하기 위해서 많은 노력이 들어간다. 그래서 조직에서 그리고 비지니스에서 꼭 필요한 핵심 지표 위주로 지표를 선정하고 집중해서 관리 하는 것이 훨씬 더 효과적이 아닌가 한다.


추가적인 분석 지표


앞서 살펴본 일반적인 지표 이외에도 모바일 서비스에 있어서 중요한 추가 지표들이 있다.


크래쉬 비율


앱의 사용자 유발하고, 앱 평가를 떨어뜨리는 요인중의 하나가  ANR(Application Not responding : 애플리케이션이 멈춰서 응답이 없는 현상) 또는 앱이 비정상 종료 되는 경우인데, 모든 케이스는 아니지만 상당 케이스는 모니터링 도구를 통해서 추적이 가능하다. 구글의 플레이 스토어의 경우에도 개발자 콘솔을 통해서 이 ANR과 DOWN리포팅 및 로그를 받을 수 있고, 아니면 야후 Flurry나 트위터의 Fabric을 통해서도 이 문제에 대한 로그를 수집 및 분석이 가능하다. 




<그림. Fabric 크래쉬 분석 화면>


앱스토어 평가


서비스의 노출을 위한 검색엔진 최적화 만큼이나 중요한것이 모바일 앱에서는 앱스토어 최적화이다. 앱스토어에 올라가는 이미지, 문구, 분류 체계 그리고 검색 노출이 쉽게 하는 기능뿐 아니라, 앱스토어에서 앱에 대한 평점 관리는 대단히 중요한 지표이기 때문에 이 부분 역시 같이 신경써야 한다.



실제 측정을 위한 절차


그러면 이런 지표들을 측정하고 사용하기 위해서는 어떠한 절차를 거쳐야 할까?


정보 모델의 설계


가장 중요한 것은 정보 모델의 설계이다. 서비스 특성을 감안하여 가장 중요한 성장 동력이 되는 지표가 무엇인지, 앞의 퓨넬 모델에서 설명한 사용자의 획득에서 수익 창출 단계까지 이르기 까지 서비스의 특성에 따라서 어떤 지표가 필요한지를 선정하고, 서비스에 맞춰서 각 지표를 정의하는 것이다.


미디어 서비스의 경우 앱 인스톨, 액티브 사용자 비율, 탈퇴 비율등과 같은 정적 지표와

사용자가 메인에서 리스트로 진입해서 컨텐츠를 보고 댓글을 쓰는 동적 이동에 따른 메인 뷰 수, 컨텐츠 뷰수, 체류 시간과 같은 동선에 따른 지표를 정보 모델로 정의할 필요가 있다.


구현 방식 선정


이러한 정보 모델이 정의 되고, 각 대표 지표가 선정이 되었으면, 이를 실제 구현할 수 있는 구현 방법을 결정해야 하는데, 모바일 데이타 분석은 빅데이타 영역에 속하기 때문에 자체 구축을 하려면 하둡이나 스파크같은 복잡한 인프라가 필요하고 대용량 데이타를 저장 및 분석하기 위한 많은 하드웨어와 인력이 필요하다.


근래에는 클라우드 서비스 형태로 제공되는 모바일 앱 분석 서비스들이 많고 광고 플랫폼을 중심으로 앞에서 언급한 구글,야후,트위터들이 무료 분석 플랫폼을 제공하기 때문에 이러한 무료 플랫폼을 이용하는 것도 하나의 방법이 된다. 

개인적으로는 Flurry를 가장 선호하는데, 사용자 수에 대한 제약이 없고 User Path, Funnel 분석등 다양한 기능을 제공한다. Google Analytics의 경우 기능이 막강하고 다양한 커스터마이제이션이 가능은 하지만 사용법 학습등에 많은 노력이 필요하고, 일정 볼륨이 넘어가면 1억원 이상의 비용을 지급하고 유료로 사용해야 하기 때문에 과연 좋은 선택인가에 대해서는 의문이 있다. 




단 이러한 플랫폼의 경우에는 커스터마이징이 어렵고 이로 인하여 대쉬 보드에 원하는 지표를 다 넣을 수 없는 경우가 많기 때문에 만들어놓더라도 각각의 지표가 연결된 의미를 찾지 못해서 무용지물화 되기 쉬운 단점이 있고, 앱스토어나 기타 흩어져있는 시스템들의 정보를 취합하여 보여줄 수 없다.


중간 대안으로는 정보분석 플랫폼을 사용하되, 이러한 분석 플랫폼들은 오픈 API를 제공하고 있고, 앱스토어도 오픈 API를 제공하기 때문에,  이러한 API를 이용하여 여러 소스로 부터 데이타를 모으고, 조직의 데이타 분석 수준이나 뷰에 적절한 대쉬 보드를 직접 구축하면 훨씬 높은 효과를 얻을 수 있다.


이벤트 태그 삽입


구현 방식이 선정되면 앱에서 발생하는 이벤트 (시작, 종료, 메인 페이지 이동, 댓글 등록)를 플랫폼으로 보낼 코드를 삽입하면 된다.


야후 플러리의 경우 간단하게 이벤트 명을 입력하는 것만으로 이벤트를 로깅 할 수 있다.


[Flurry logEvent:@“EVENT_NAME"];


<코드. 야후 플러리 이벤트 로깅 iOS Object C 예제>


이때 솔루션에 따라 이벤트의 개수와 이벤트의 길이에 제약이 있기 때문에, 정보 모델을 설계할때 적절한 이벤트 수를 정하는 것이 중요하다. (플러리의 경우 300개의 이벤트, 이벤트 명은 255자 이하)

이벤트 명을 정의할때는 정보 모델에 따라서 트리 구조로 계층 구조를 갖는게 좋은데 예를 들어


/main

/main/contents/

/main/contents/comment


식의 REST 형식의 리소스 형태를 사용하게 되면, 훨씬 더 직관적으로 이해 쉽다.



맺으며


모바일건 웹이건 근래의 서비스는 경쟁이 심해지고 빠르게 사용자의 니즈를 이해하고 맞춰나가지 않으면 생존하기 힘든만큼 데이타 분석은 선택이 아니라 거의 필수적이다. 


이러한 데이타 분석은 갑자기 튀어난게 아니라 Dataware house, Business Intelligence, OLAP 등으로 예전 부터 전통적으로 존재하고 있는 시스템이고 다만 구현 방식이나 강조되는 포인트들이 다소 변경된것인데, 경험상으로 보면 이런 시스템을 구현하는 데 많은 비용과 노력을 들이지만 100% 잘 사용되는 경우가 드물다. 

 원인을 보면, 시스템을 구축하지만 이 구축된 정보를 얼마나 쉽게 전달할것인가에 대한 고려가 적고 지표에 대한 이해와 시스템 사용 방법에 대한 교육이 없이 한정된 배경 지식만으로 전체 지표를 이해가 불가능 하기 때문이다.

 시스템을 보는 입장에서 최대한 단순하게 만들어야 되는데, 경험상 BI 프로젝트등을 해보면 멋진 대쉬보드를 만들어놓고도 결국 끝에 가서 나오는 말은 액셀로 보내주세요... 이다.

 시스템의 구축이 전체의 30% 이하 정도의 작업이라면 나머지는 필요한 지표의 정의, 정보 모델의 정의, 사용자가 원하는 대쉬보드의 구축, 구성원들에 대한 데이타 분석 및 시스템에 대한 활용 교육이 지속적으로 제공되어야 한다. 큰그림을 이해하지 못한 상태에서 파편만 보다가는 전체 흐름이나 방향을 놓칠 수 있기 때문에 이 부분에 대해서는 몇번을 강조해도 부족함이 없을것이라 본다.  

저작자 표시 비영리
신고

MySQL 클러스터링을 위한 Galera Cluster

아키텍쳐 | 2015.11.18 23:52 | Posted by 조대협

MySQL Galera Replication


조대협 (http://bcho.tistory.com)


RDBMS 오픈소스 중에서 단연 가장 많이 사용되는 것은 MySQL인데, 근래에 웹 스케일이 커지면서, 단일 인스턴스로만 서비스가 불가능한 용량까지 가게 되서, 이 MySQL에 대한 클러스터링 스케일링에 대한 이슈가 많아졌다. 이에 Tungsten, MySQL Replication, NDB, Galera 등 다양한 클러스터링 방법이 있는데, 그중에서 갈레라 클러스터링 (Galera Clustering)에 대해서 간단하게 정리하고자 한다.


MySQL Replication


갈레라 클러스터링을 이해하기에 앞서서 먼저 가장 널리(그리고 쉽게) 사용되는 MySQL Replication 방식에 대해서 알아보자. MySQL Replication 방식은 Master/Slave 방식의 구성이 일반적이며, 이 구성의 경우 특정 노드는 쓰기를 담당하고 나머지 노드는 읽기를 담당하는 형태로 구성이 된다.

통상적으로 데이타 베이스 트랜젝션의 60~80%가 읽기 트렌젝션이기 때문에, 이러한 구조를 사용하더라도 충분히 성능의 향상을 기대할 수 있다.


다음 그림은 MySQL Replication 의 간단한 구조도 이다.

 




먼저 좌측의 Master Node에 쓰기 트렌젝션이 수행되면 Master node는 데이타를 저장하고, 트렌젝션에 대한 로그를 내부적으로 BIN LOG라는 파일에 저장한다. (시간 순서대로 수행한 업데이트 트렌젝션이 기록되어 있다.)


Slave Node에서는 이 BIN LOG를 복사해온다. 이 복사 작업을 IO Thread라는 스레드가 수행하는데, 이렇게 읽어온 내용은 Replay Log라는 파일에 기록이 된다. 이렇게 기록된 내용은 SQL Thread라는 스레드가 읽어서, 하나씩 수행을 해서  MySQL 데이타 파일에 기록을 한다.


쉽게 설명하면, insert 쿼리를 master node에서 실행했으면 그 쿼리가 master node의 bin log에 기록이 되고, 이 내용은 slave node에 복사가 된후에, slave node에서 같은 쿼리가 수행이 되서 복제가 반영되는 방식이다.


방식이 단순해서 신뢰도가 높은 반면, 단점으로는

  • 읽기와 쓰기 노드를 분리해야 하며,
  • 데이타 복제가 동기 방식이 아닌 비동기 방식으로 적용된다. 바꿔서 말하면, master node에 적용한 데이타 변경사항이 slave에 반영될때까지 일정 시간이 걸린다는 것으로, master와 slave node간의 순간적인 데이타 불일치성이 발생할 수 있다는 것이다.


Galera cluster


Galera cluster는 http://galeracluster.com/ 에서 제공되는 오픈소스로, 동기방식의 복제 구조를 사용하고 있다.

간단하게 구조를 살펴보자 아래 그림을 보면 




각각의 노드가 있을때, 아무 노드에나 쓰기나 업데이트가 발생하면, 모든 노드에 데이타를 복사를 완료하고 나서, 업데이트 내용이 파일에 저장된다. 아키텍쳐상의 구조를 보면, 위의 그림과 같이 각 MySQL 노드에는 WSREP 라는 모듈이 있다. 이 모듈은 데이타베이스에 복제를 위한 범용 모듈로 여기에 마치 드라이버처럼 Galera replication module을 연결해주면 데이타 변경이 있을때 마다, 이 Garela replication module이 다른 mysql node로 데이타를 복제한다.


약간 더 구체적인 구조를 살펴보면 노드간의 데이타 복제는 다음과 같은 흐름을 따르게 된다. 





노드에 트랜젝션이 발생하고 COMMIT이 실행이되면, 디스크에 내용을 쓰기 전에 다른 노드로 복제를 요청하고 다른 노드에 복제 요청이 접수되었을때, 해당 노드의 디스크에 실제로 데이타를 쓰게 된다.


이러한 특성으로, 전체 노드에 데이타가 항상 일관성있게 저장되고, 모든 노드가 마스터 노드로 작동을 하며, 특정 노드가 장애가 나더라도 서비스에 크게 문제가 없다. 

(MySQL Replication의 경우 마스터 노드가 장애가 나면 슬레이브 노드중 하나를 마스터로 승격을 해야하는 등 다소 운영 프로세스가 갈레라에 비해서는 복잡하다.)


상당히 좋아 보이는 구조이기는 한데, 반대로 가지는 단점도 만만하지 않다.


성능

먼저 성능적인 부분에서, 데이타를 디스크에 저장하기 전에, 다른 모든 노드에 데이타 복제 요청을 해야 하기 때문에, 비동기 방식의 MySQL Replication에 비해서, 쓰기 성능이 떨어지는 것으로 보인다.


장애 전파

이렇게 다른 노드에 복제 요청을 하는 클러스터 구조의 경우, 장애를 다른 노드로 전파 시킬 가능성이 높은데, 예전에 대표적인 웹 애플리케이션 서버인 웹로직의 경우 유사한 세션 클러스터링 구조를 사용했다. 

이 경우 복제를 요청했을때 복제 요청을 받은 노드가 장애 상황 특히 느려지거나 일시적으로 멈췄으때, 복제를 요청한 노드가 응답을 받지 못하고 대기하게 되고, 이 대기한 노드에 다른 노드가 복제를 또 요청하면, 같은 이유로 복제가 지연 되면서 클러스터를 타고 장애가 전파되는 현상을 야기하게 된다.

그래서 갈레라 클러스터의 경우 LOCK문제가 생기거나 슬로우 쿼리들이 많이 발생할때 장애를 전파시킬 수 있는 잠재적인 문제를 가지고 있다.


스케일링의 한계

갈레라가 모든 노드에 데이타를 복제하고 트렌젝션을 끝내는 만큼, 전체적인 노드수가 많아지게 되면, 복제를 하는데 그만큼 시간이 많이 걸림에 따라, 하나의 클러스터에서 유지할 수 있는 노드의 수가 한계가 있어져서, 횡적 스케일링의 한계가 올 수 있다. 


이런 단점에도 불구하고, 모든 노드에 읽기 쓰기가 가능한 멀티 마스터 구조와 모든 노드의 데이타를 일관적으로 유지 시켜준다는 장점과 쉬운 설정 방법으로 인하여 MySQL 클러스터를 구성한다면 한번쯤 검토해봐야 하는 솔루션이 아닌가 한다.


(아쉽게도 국내 사례는 그다지 많지 않은듯...)


몇가지 참고 사항

  • 갈레라 클러스터는 서로 다른 MySQL 버전간에도 클러스터로 묶을 수 있다.
  • 갈레라 클러스터에서 노드가 떨어졌다가 붙으면 일정 부분은 GTID (Global Transaction ID)를 이용하여, 데이타가 복제 되지 않은 델타 부분만 복제가 가능하지만, 시차가 오래되 버리면 풀 백업본을 가져다 엎어야 한다. (풀백업은 복구는 시간이 많이 걸림)




저작자 표시 비영리
신고

'아키텍쳐' 카테고리의 다른 글

MySQL 클러스터링을 위한 Galera Cluster  (3) 2015.11.18
요구 사항 정의 기법  (0) 2013.11.13
소프트웨어 개발팀의 구조  (0) 2013.11.01
Technical Debt  (1) 2013.10.30
License Key Management  (0) 2013.08.01
암호화 알고리즘 속도 비교 (대칭키)  (0) 2013.07.17

모바일 개발 트렌드

아키텍쳐 /모바일 | 2015.11.17 10:55 | Posted by 조대협


모바일 개발 트렌드에 대한 예측


조대협 (http://bcho.tistory.com)


시장 환경


2016년 모바일 개발 트렌드에 대해서 언급하기 앞서서 전체적인 모바일 비지니스 변화를 지켜볼 필요가 있다.


모바일 스타트업 중심의 개발 트랜드가 계속


여러 유니콘(실리콘 밸리에서 급속도로 성장하고 있는 스타트업)들의 실적 약화에도, 내년에도 변함없이 계속해서 스타트업 생태계는 확장이 되어갈 것이고, 그 중심에 모바일 앱이 있을 것 이라고 본다.

많은 모바일 앱들은 톡톡 튀는 아이디어와 새로운 기술들로 무장한 스타트업을 중심으로 개발이 될것이라고 보는데, 모바일 스타트업의 특성상 필요한 몇가지 요구 사항이 있고, 이 요구 사항을 채워주는 기술 위주로 내년은 기술 트랜드가 발전하지 않을까 싶다.


모바일 중심의 스타트업 비지니스에서 개발팀이 필요한 내용을 정리해보면 다음과 같다.


효율성과 스피드가 점점 중요시 됨

스타트업의 본질적인 특성상 적은 인원으로, 개발을 해야 하고, 시장에 많은 경쟁 서비스들과 우위를 점하기 위해서는 스피드가 중요하다. 적은 인원으로 스피드를 내려면, 팀의 효율성이 중요하다. 그래서 효율성을 최대로 할 수 있는 개발 프로세스가 필요하고, 빠르게 배우고 빠르게 사용할 수 있는 기술이 필요하며, 시스템 운영등을 대행해주는 서비스들이 필요하다.


고객 피드백과 실험

근래에 스타트업 아니, 비단 스타트업 뿐 아니라 대부분의 서비스 개발 방식은 “린 스타트업” 방식을 따르는데, 최소한의 기능을 가진 제품을 시장에 출시하고, 그 기능을 피드백을 기반으로 계속해서 보강해 나가는 서비스 개발 프로세스를 가지게 된다.

이 프로세스를 실현화 하려면 새로운 기능이나 UX등에 대해 사용자로 부터 피드백을 받을 필요가 있고, 다양한 옵션에 대해서 실험과 분석을할 필요가 있다. 

이런 실험과 분석을 하기 위해서는 사용자에 앱 사용 패턴을 분석할 수 있는 분석 플랫폼과, 다양한 기능을 테스트할 수 있는 테스팅 플랫폼이 필요하게 된다.


글로벌 서비스

모바일 앱 서비스의 수익 모델을 보면 인앱 결재도 많지만, 아직까지는 광고에 의존하는 모델이 상당히 많다. 이 경우, 한국 시장만 보기에는 시장 규모가 너무 작고, 애플리케이션 성의 앱들은 특별히 한국이라는 시장에 갖혀 있을 필요가 없기 때문에 글로벌로 서비스를 확장하거나 처음부터 아예 글로벌을 타케팅 하는 경우가 많은데, 개인 정보 위치에 대한 속지 주의 (개인 정보는 그 나라를 떠자니 못한다) 요건이나 각 나라의 문화나 계정 체계 (동남아는 라인 로그인을 많이 쓰고, 한국은 카톡 로그인, 미국은 페북 로그인을 많이 쓰는)나 기술적 차이 (중국에서는 구글이나 애플 푸쉬가 작동하지 않는다)로 인하여 각 국가에 맞게 애플리케이션을 수정해야 할 필요가 있다. 


개발 트랜드


그러면 이런 니즈를 맞추기 위해서 개발 트랜트는 어떻게 변화하고 있을까?


클라우드 활용의 가속화

첫번째는 클라우드 서비스 활용의 가속화이다.  클라우드 서비스의 활용은 어제 오늘일이 아닌 이미 보편화된 내용인데,  그렇다면 변화는 무엇인가? 클라우드 서비스 활용이 주로 서버등의 인프라를 활용하는 IaaS 중심이었고, 근래에는 웹서버나 데이타베이스 서버등의 미들웨어를 활용하는 PaaS 형태로 그 중심이 옮겨왔다.

예전에는  아마존의 EC2등에 직접 솔루션을 설치해서 개발을 했는데, 요즘은 그보다  아마존 Beans Talk이나 Heroku 클라우드 같은 PaaS 형태의 사용이 잦아졌고, Redis나 MongoDB등과 같은 다양한 솔루션들이 PaaS 형태로 제공되어 많은 미들웨어를 직접 설치하지 않고 managed 서비스를 사용하는 형태로 이동하고 있다. 이는 복잡한 인프라에 대한 설치 및 운영 비용을 줄이고, 빠른 개발을 할 수 있게 도와준다.

 대표적인 서비스로는 아마존 BeansTalk, IBM BlueMix, Heroku 클라우드등을 예로 들 수 있다.


여기에 한걸음 더 나가서 Fundamental 서비스의 활용이 두드러 지는데, Fundamental 서비스는 애플리케이션을 구성하는데 사용되는 기능을 제공하는 서비스로 대표적으로 푸쉬 서비스, 메세지 큐 서비스, 사용자 계정 관리 서비스등이 이에 해당한다. 특히 이러한 서비스는 여러가지 복잡한 기능들을 추상화해주기 때문에 여러가지 기능들을 동시에 지원해야 하는 경우 쉽게 개발을할 수 있게 해준다. 대표적인 예로는 푸쉬 서비스를 들 수 있는데, 푸쉬는 기본적으로 안드로이드와 iOS를 위한 GCM,APNS 푸쉬 지원뿐 아니라, 중국을 위한 바이두 푸쉬등 다양한 푸쉬를 지원해야 하며, 대량 발송, 예약 발송등 복잡한 기능들을 제공해야 하는데, 이를 일일이 개발하려면 그것만으로도 하나의 제품을 개발하는 정도의 개발 노력이 필요하다. 이러한 고급 기능들이 근래에는 클라우드로 제공되는데, 아마존의 SNS와 같이 대형 클라우드 벤더에서 Fundamental 서비스로 제공하는 기능이나 또는 OneSignal.com 과 같이 특정 도메인(기능)에 전문화된 형태로 서비스가 제공 되는 경우가 있다.


 대형 벤더에서 제공되는 Fundamental 서비스는 해당 클라우드 인프라와 같은 위치에서 서비스가 제공되고 같은 인프라를 사용하기 때문에 통합이 쉽다는 장점을 가지고 있지만 반대로 특정 도메인 기능만 제공하는 전문화된 서비스에 비해서 가격이나 기능적인 면에서 열세인 경우가 많다.


대표적인 서비스로는 앞에서 언급한 푸쉬 전문 서비스인 OneSignal.com , 동영상 인코딩 서비스 heywatch.com, zencoder.com , Redis 전문 서비스인 redislabs.com , 몽고디비 및 DBaas 서비스 전문업체인 compose.io , 검색 전문 서비스인 https://www.algolia.com/ 등을 들 수 있다. 


여담으로 나이가 많은 개발자들은 기술을 탐독하고, EC2등에 직접 깔아서 사용하는 것을 선호하는 반면, 근래에 많은 스타트업 개발자들을 만나서 개발 아키텍쳐를 검토하다보면, 오히려 잘 구성되어 있는 매니지드 서비스들을 잘 엮어서 빠른 시간내에 더 좋은 기능으로 서비스를 개발하는 것을 보면, 세대간에 기술에 대한 접근 방법이 벌써부터 차이가 나지 않는가 한다.



풀스택 개발자

풀스택 개발자란 한명의 엔지니어가 독립적으로 모든 서비스를 개발할 수 있는 수직적인 기술 능력을 가지고 있는 사람을 정의한다. 수직적인 기술 능력이란, 앱-백앤드-인프라 또는 프론트-백앤드-인프라 까지 서비스를 개발하는 데 필요한 모든 End to End  기술을 이야기 한다.

작년까지만 해도 풀스택 개발자가 바람직하다 아니다 라는 논쟁에서 부터, 풀스택 엔지니어는 불가능하다 가능하다 까지 여러 논쟁이 많았다.

결론 부터 말하자면 풀스택 개발자가 가능하고 불가능하고, 바람직하고 말고의 논쟁을 떠나서, 할 수 밖에 없다.


스타트업 인원 구조의 특성상 각 기술 계층에 해당하는 엔지니어를 따로 뽑을 수 가 없기 때문에 한명의 개발자가 앱 개발에서 부터 백앤드 개발까지 모두 맏아야 하며, 시스템을 운영하기 위한 인프라 설치 및 운영까지 모두 커버해야 한다. 


이런 것이 가능한 것은, 스타트업 인력 구성의 한계에 의한 필요성도 있지만, 이런 필요성에 의해서 기술도 그만큼 편리해졌기 때문이다. 스크립트 언어의 발전으로 루비나 node.js 의 경우 학습 비용이 매우 낮고, 생산성이 높게 개발을 할 수 있으며, 아울러, 클라우드의 발전으로 전문적인 하드웨어 전문적인 지식이 없이도 얼마든지 인프라를 운영할 수 있고 더불어 PaaS의 발전으로 하드웨어의 지식이나 미들웨어에 대한 지식이 없이도 설치 및 운영이 가능하게 되었다.


개인적으로 풀스택 개발자의 가능성에 대해서 많은 고민을 했는데, 스타트업에서 만난 엔지니어들을 보면 앱 개발에서 시작했다가 필요로 인하여 서버를 개발하게 되고, 쉬운 방법을 찾아가면서 클라우드를 활용하면서 서버 개발까지 같이 하는 개발자들을 많이 보았다. 특히나 백앤드 개발에 대한 선입관이 없기 때문에 솔루션이나 아키텍쳐 구성에 유연성이 보이고, 기존 전통적인 백앤드 아키텍쳐의 사상을 넘어서는 좀더 실용적인 아키텍쳐 디자인을 하는 것을 볼 수 있었다.


서비스 기반의 데이타 분석

근 몇년 빅데이타 분석의 중요성은 계속 강조되어 왔기 때문에 데이타 분석의 필요성등에 대해서는 별도로 언급하지는 않겠다. 그런데 이 데이타 분석이라는 것이, 많은 양의 데이타를 저장하기 위한 하드웨어 인프라가 필요함은 물론이고, 이를 분석하기 위한 소프트웨어 예를 들자면 하둡이나 스팍과 같은 기술을 도입하기 위해서는 높은 기술 수준과 자금이 필요하기 때문에 일반적인 스타트업에서는 적용이 매우 어렵다. 그래서 빅데이타라는 넘어가야 하는 영역이 있음에도 불구하고 실제로 활용하기가 어려운 영역이었다.

그런데 근래에 광고 서비스 업체나 인터넷 서비스 업체를 중심으로 데이타 수집에 대한 요구와 개발자 생태계를 자기쪽으로 끌어들이기 위한 목적으로 데이타 분석 서비스를 무료 또는 부분 무료로 오픈 하는 경우가 많다.


대표적인예로, 구글 애널러틱스 (aka. GA)나 야후의 Flurry, 트위터의 Fabric과 같은 서비스들이 대표적인 예이며, 한국의 경우 파이브락스(http://www.5rocks.io/en) 가 무료(광고를 내보내야하기는 하지만)에서 서비스를 제공하고 있다. 



< 그림. Yahoo Flurry 스크린샷 >


단순하게는 일/월 방문자수 (DAU/MAU)에서 부터, 사용자가 앱에서 어떤 경로로 돌아다니고 머무는 시간이 얼마인지, 사용자 층은 어떻게 되는지까지 분석이 가능하다.

앱을 개발해서 서비스를 한다면 반드시 사용해야 하는 서비스가 아닐까?


AB 테스팅의 도입 가속

페이스북을 사용하는 사용자라면 어느날 갑자기 앱 업데이트를 하지 않았는데도 새로운 기능이 돌다가 갑자기 그 기능이 없어진것을 확인할 수 있다. 페이스북에서는 사용자의 반응을 살피기 위해서 새로운 기능을 미리 넣어서 배포해놓고,사용자를 A/B 두 그룹 (또는 그 이상)으로 나눠서 사용자의 기능 사용에 대한 반응을 보고 그 기능을 적용할지 여부를 결정하는 방법이다.


A/B 테스팅은 개념 자체는 좋지만, 앱스토어 환경에서 이를 하려면, 

  1. 두개의 기능을 개발해야 하고
  2. 각 기능을 A/B 두개의 사용자 그룹에 별도로 보이게 해야 하며
  3. A/B 사용자에 대한 기능 사용율을 매번 수집하여 분석해야 한다.


물론 직접 코드로 만들 수 도 있지만, 배포된 애플리케이션에서 테스트 비율을 조정한다던지, 테스트 진행 상황에 대한 리포팅을 작성하려면 로그도 수집해야 하고 별도의 개발 노력이 드는게 사실이기 때문에, 막상 쉽게 접근하기는 어렵다.


이런 일반적인 AB 테스팅 개발을 제공하기 위한 클라우드 기반의 서비스가 근래에 들어서 많이 제공되고 있는데, optimizely.com apptimize.com 등 여러 서비스들이 있고, 아마존 AB 테스팅의 경우 무료로 그 기능을 제공한다.

아마존의 경우는 무료인 만큼 기능이 빈약하다. 상용 서비스의 경우에는 5만, 10만 사용자까지 무료로 기능을 제공하거나 수익을 내지 못하거나 펀딩을 받지 못한 스타트업에는 무료로 제공하는 경우도 있으니, 꼼꼼하게 살펴볼 필요가 있다. 


  

<그림. AB 테스팅 도구에서  UI를 변경하는 화면> 

출처 : https://www.leanplum.com/c/blog/page/2/


특히 상용 솔루션의 경우에는 앱이 배포된 상태에서 별도의 재 배포 없이 UI 요소 (버튼 색, 이미지, 텍스트)를 동적으로 변경해서 테스트를 진행할 수 있는 기능을 제공하기 때문에, 손쉽게 UI 개선을 해나갈 수 있고, 특히 GUI 기반의 도구를 제공하기 때문에, 개발팀의 도움 없이 디자인팀이 직접 수정을 해서 테스트가 가능하다.


개발에 대한 공수나, 적절한 플랫폼의 부재로 지금까지 쉽지 않았던 분야인데, 여러 클라우드 기반의 서비스를 기반으로해서 2016년에는 일반 앱 서비스 개발에도 사용 빈도가 꽤 높아지지 않을까 하는 예상을 조심스럽게 해본다.

오픈 소스 머신 러닝 알고리즘 및 클라우드 머신 러닝 서비스


데이타 분석의 다른 영역으로는 데이타를 분석하여, 추천이나 데이타등을 군집화 또는 분류해주는 머신러닝 (Machine Learning) 분야가 있다. 수학적인 지식과 대규모 인프라가 필요하기 때문에, 일반적인 기업이나 개발자들이 접근하기 어려운 부분이었는데, 근래에 하둡과 같은 빅데이타 인프라가 오픈소스화 되고, 또한 복잡한 ML  알고리즘이 오픈소스 패키지로 제공됨에 따라서 급격히 확산이 되기 있는데, 여전히 소규모의 앱 개발자들이 쓰기에는 복잡한 인프라를(하둡,스파크 등) 직접 설치 운영해야 하는 부담이 있었다.

 그러나 근래에 Microsoft 나 Google 등을 중심으로 이 머신 러닝 알고리즘을 클라우드 서비스 형태로 API가 제공됨으로써 개발 접근성이 매우 쉬워졌고, coursera.org 와 같은 온라인 강의를 통해서, 일반 개발자들오 머신러닝 관련된 기술을 쉽게 배울 수 있는 온라인 강좌됨에 따라, 예전에 비해서 훨씬 쉽게, 빅데이타를 활용한 머신러닝 서비스에 접근이 가능하게 되었다. 




<그림.  Microsoft Azure 클라우드의 머신러닝 로직 설계 화면 >




지금까지 짧게지만 앞으로는 모바일 서비스 개발 방향에 대해서 살펴보았다.

전체적인 흐름을 요약해보자면, 스타트업 주도의 개발이 활성화 되면서 적은 인원으로 효율적인 개발을 할 수 있는 환경이 필요함에 따라 앱 개발자가 스크립트 언어등 러닝 커브가 낮은 언어를 이용하여 서버쪽에 구현을 같이하는 풀스택 개발자 형태로 전환되는 현상이 가속화될 것이고, 이에 맞물려서 쉽게 인프라를 사용할 수 있게 하는 클라우드 컴퓨팅 환경의 활용이 플랫폼 형태로 되어 있는 PaaS를 중심으로 활용될것이다.

또한 빅데이타에 대한 활용 부분이 대기업 뿐 아니라, 저 자본에 소인원인 스타트업 앱 개발에도 사용이 되는 대중화의 국면을 맏을 것이라고 보는데, 클라우드 서비스 형태로 제공되는 빅데이타 분석등의 플랫폼을 중심으로 무료 또는 저 비용의 서비스가 활용 될것이며, AB 테스팅 서비스의 활성화로 사용자의 반응을 기반으로 하는 개발이 가속화 될것으로 보인다. 또한 고급 머신 러닝 알고리즘이 오픈소스화 되고, 서비스 API화 되면서 대중화 국면을 맞을 것이다.


저작자 표시 비영리
신고

대용량 서비스의 트래픽을 줄이는 이미지 최적화 기술 Web-P


조대협 (http://bcho.tistory.com)





대용량 트래픽 서비스를 하다보면, 항상 고민하게 되는 것이 인프라 운영 비용에 대한 문제이다.

특히 미디어 서비스의 경우, 네트워크 트래픽을 유발하는 이미지나 동영상에 대한 CDN과 네트워크 비용이 문제가 되고, 사용자 입장에서도 모바일 3G/LTE 망을 통해서 이미지나 동영상을 다운로드 받는 경우, 데이타 사용량에 실제로 연관이 되기 때문에 점점 더 멀티미디어 파일 포맷에 대한 용량 최적화가 문제로 대두 되고 있다.


그중에서, 이미지 압축 방식으로 GIF,JPEG/PNG을 대체할 이미지 포맷으로 BNG,구글 Web-P, Microsoft JPEG-X 등이 소개되고 있는데, 이 중에서 Web-P에 대해서 소개하고자 한다.


기본적으로 JPEG는 손실 압축 기술로, 이미지를 압축했을때, 손실이 발생한다. 특히 텍스트나 정교한 내용이 있을때, 그 내용이 뭉게지는 현상이 있을 수 있지만, 큰 사진이나 일반적인 이미지를 표현하는데 좋고 색 단계를 여러가지 표현할 수 있기 때문에 사진이나 일반 이미지 저장 포맷으로 많이 사용된다.


GIF의 경우 무손실 압축 알고리즘이기 때문에 텍스트가 들어간 이미지등에는 유리하지만, 256 색까지만 표현이 되지 않기 때문에 사진등에는 유리하지 않지만, 움직이는 영상(움짤/Animated GIF)등으로 많이 주목받고 있다. (그런데 이 움짤 용량이 무지 크다.)


JPEG,BPG,Web-P를 비교해보면, 

압축률을 BPG > Web-P >> JPEG 순으로,  BNG 가 가장 압축률이 좋고, 또한 압축된 이미지의 품질또한 가장 높다.


잠재적인 위험이 있는 BPG


그렇지만 문제는 BPG는 내부적으로 HEVC라는 기술을 사용하는데, 이 기술은 MPEG(동영상 압축) 기술의 일부로, 특허가 복잡하게 얽혀 있는 가능성이 있는 것으로 알려져있다. (실제로 BPG 사이트에 들어가도 그렇게 공지하고 있다.) MPEG 기술 안에는 너무 많은 특허가 들어가 있어서 당사자도 특허 참여 여부 또는 제품에 그 특허가 들어갔을때 침해를 당했는지도 찾기 어려워서 MPEG-LA라는 특허관리 업체에서 MPEG 특허를 관리하고, 문제가 생기면 소송을 통해서 특허 권리금을 받아서 MPEG-LA 참여 업체에 특허 권리료를 나눠 준다. 특허 권리에 대해서 BPG 를 개발한 사람이 낸 의견 중의 하나는 HEVC 기술을 하드웨어 가속 기능에 탑재해서 하드웨어 업체 또는 드라이버 업체가 특허를 물면된다는 논리는 내세우고 있는데, 라즈베리파이 같은 저사양 하드웨어등에서 이런일이 가능할까 의문이다. 개인적인 생각으로는 BPG는 특허에 대한 위험성 때문에 널리 확산되기가 어렵지 않을까 싶다.


구글의 Web-P


Web-P는 구글에서 만든 압축 기술로, JPEG에 비해 높은 압축률과 투명 이미지와 GIF 처럼 움짤을 지원한다.

대략 움짤 gif를 web-p로 줄이게 되면 대략 1/4 정도로 사이즈가 줄어드는 효과가 있다




<그림. WebP와 JPEG 화질 비교>

출처 : https://developers.google.com/speed/webp/gallery


아직 브라우져 커버리지는 높지는 않지만, 크롬이나 Opera 등에서 일부 지원하고 있고, Android 플랫폼에서도 지원하고 있다. 




출처 : http://www.slideshare.net/guypod/high-performance-images-beautiful-shouldnt-mean-slow-velocity-eu-2015



또한 재미있는 것중의 하나는 구글에서 제공하는 웹 최적화 플러그인인 페이지 스피드 https://developers.google.com/speed/pagespeed/module/ 플러그인에서, 브라우져의 web-p 지원 여부에 따라서 기존의 JPEG를 web-P로 자동 변환하여 내려주는 기능을 제공하여, 별도의 인프라에 큰 변화를 주지 않고도 web-p를 지원하는데 큰 문제가 없다. 지원이 안되는 브라우져의 경우에는 javascript를 이용하여, web-p를 지원하게 할 수 도 있다.


전체 이미지를 web-p로 바꾸는 것은 무리가 있겠지만, 모바일을 기준으로 볼때 안드로이드 점유율이 상당하기 때문에, 안드로이드 디바이스에만이라도 선별 적용하게 하는것만으로도 용량을 줄이는 큰 효과가 있지 않을까 한다.


참고 : WebP 관련 자료 - https://developers.google.com/speed/webp/

저작자 표시 비영리
신고

마이크로서비스 아키텍쳐에 대한 소고



간만에 낚시성 제목을 달아봤는데, MSA (마이크로 서비스 아키텍쳐)가 필수라는 이야기는 꼭 틀린말이라고 볼 수 는 없습니다. 특히나 개발팀의 규모가 큰 경우나, 지리적으로 개발팀이 나눠져 있는 경우에는 서비스 단위로 나눠서 각 팀이 서비스를 개발하고, 독립된 기술과 개발 체계를 가지면서 빠르게 개발해 나가는게 효율적이기 때문에, 규모가 어느정도 되는 팀에서는 효율성이 높습니다.


중앙에서 통제할 필요 없이, 각자가 알아서 설계하고, 만들고, 테스트 하고 운영하기 때문입니다.

이것을 분산 거버넌스라고 하는데, 관리나 의사결정의 권한을 중앙의 팀이 중앙 통제하지 않고, 각자의 팀에 자율적으로 맏기고, 책임도 맏긴다는 이야기 입니다.


그러면 분산 거버넌스를 하면,중앙 거버넌스가 필요하지 않냐?


MSA글을 보면, 보통 분산 거버넌스와 이에 대한 필요성과 장점에 대해서만 이야기를 한다.

그러나, MSA에 과연 중앙 거버넌스가 필요하지 않을까?


개인적인 생각으로는 이 또한 강한 중앙 거버넌스가 필요하다.

첫번째로, API로 서비스를 제공하기 위해서는 API 표준이 맞아야 한다. 헤더 구조, URI 컨벤션, Granuality (서비스 크기), 에러 추적을 위한 로깅 메세지의 표준화가 필요하다.

두번째로, 서비스의 기능에 대해서, 어떤 기능이 필요한지, 필요하다면 기능이 어떤 동작을 어떻게 하는지에 대한 정확한 스펙에 대한 정의가 필요하다 이건 서비스를 제공하는 팀 보다는 서비스를 사용하는 팀 입장에서 해야 한다.

세번째로, 이러한 서비스를 엮을려면, 필요에 따라서 aggregation API를 만들거나 또는 서비스 자체에 기능을 추가해야 하는데, 팀 이기주의로 인하여 타팀으로 일을 떠넘기는 현상이 생길 수 있기 때문에 중앙에서 이를 조율할 필요가 있다.


실제로 MSA와 유사한 구조로 서비스를 개발해본 경험으로 보면, 이러한 중앙 통제가 필요하고 거기에 드는 추가적인 비용 (코디네이션/조율)이 만만하지 않다.


또한 다른 문제점중의 하나는 각 서비스팀별 개발 수준이나 품질 수준이 다르기 때문에, 기능을 추가하고자 할때도 어느 서비스(즉 팀으로 보낼것인가)를 고민해야 한다는 것이다.


MSA의 도입은, 각 서비스 개발팀의 수준이 높아야 권한을 분산할 수 있고, 또한 중앙집중형 거버넌스 조직을 통해서 표준화등이 강력하게 이루어져야 한다.


결론적으로 난이도가 높은 아키텍쳐 스타일이라는 이야기이고, 전사 개발팀 차원에서의 많은 투자가 필요할듯 하다.


SSAG에서 토론글 중, 홍성진님이 재미있는 링크를 올려주셔서 첨부합니다

http://siliconangle.com/furrier/2011/10/12/google-engineer-accidently-shares-his-internal-memo-about-google-platform/


저작자 표시 비영리
신고

아키텍쳐 문서화는 어떤 도구를 사용하는게 좋을까?

조대협(http://bcho.tistory.com)


제 현재 본업은 아키텍트 입니다. 주로 시스템을 설계하는 역할을 하는데, 이 아키텍쳐 문서를 주로 PPT를 사용합니다. 문서는 워드로 만드는게 좋을 수 도 있고, EA나 StarUML등등 많은 툴이 있는데,  굳이 PPT를 사용하는 이유를 적어놓고자 합니다.

사실 예전에는 MS WORD로 설계문서를 만들었습니다. 만들어 놓으면 멋도 있고, 자세한 내용 표현이 가능해서 탐독하면서 이해하기도 좋습니다. 

그런데, 고객사의 요구 때문에, PPT로 바꾼후, 거의 습관처럼 PPT로 아키텍쳐 문서를 만들다 보니, 몇가지 장점이 있습니다.





1. PPT 는 표현에 제약이 없다.

아키텍쳐 디자인은 특성상 많은 다이어그램과 노트등을 달아야 하는데, WORD로 작성할 경우, 다른 툴에서 다이어그램을 그린 후 가져다 붙여야 합니다. 문서 만드는데 여간 노력이 많이 들어가고, 또한 UML 도구 같은 것을 사용하면 그 도구에서만 제공하는 다이어그래밍이 가능하지 다양하고 쉬운 다이어그래밍이 어렵습니다. 그냥 그리고 싶은 데로 표현하고 싶은데로 자유롭게 하면 되니 일단 문서 작성이 쉽습니다.


2. PPT는 발표용이지 문서용이 아니다

SI때나, 예전 전통적인 개발 방법론에서는 아키텍쳐 설계서 산출물이 나오면 이걸 받아서 개발자들이 잘 읽고 개발을 시작하는 프로세스였다면 근래의 개발 프로세스는 아키텍트가 설계를 하고,이 내용을 개발자들에게 설명을 합니다.

그냥 문서 하나 휙던지고 마는게 아니라는 겁니다. 예전 포스팅에서도 몇번 언급했지만, 문서화는 커뮤니케이션을 원할하게 하기 위한 하나의 도구이지, 산출물이 목적이 아닙니다.

그런점에서 PPT는 발표를 위한 도구인점에서 메리트가 많습니다. 보고용 자료가 아니라 발표/토론용 자료를 만드는 게 아키텍쳐 문서화의 목적이면 거기에 맞는 툴을 쓰는게 맞기 때문입니다.



저작자 표시 비영리
신고

MSA 아키텍쳐 구현을 위한 API 게이트웨이의 이해 #2

API 게이트웨이 기반의 디자인 패턴

조대협 (http://bcho.tistory.com)



API 게이트 웨이는 여러개의 엔드포인트를 설정하고, 각 엔드포인트 마다 메세지 흐름을 워크 플로우 엔진 설정을 통해서 API 에 대한 Mediation, Aggregation 설정을 할 수 있는 미들웨어 이다. 쉽게 말하면 설정과 프로그래밍이 가능한 툴일 뿐이다. 그래서, API 게이트 웨이를 도입한다고 게이트웨이가 재 역할을 하는 것이 아니라, 게이트웨이 를 이용하여 적절한 게이트 웨이 아키텍쳐를 설계해야 한다. 


여기서는 API 게이트 웨이를 이용한 아키텍쳐 설계시 참고할 수 있는 디자인 패턴에 대해서 소개 한다. 

※ 이 패턴들은 예전에 ESB 기반으로 SOA 프로젝트를 했을 때 사용했던 패턴으로 일반적인 이론이 아니라 실제 적용 및 검증을 거친 패턴이다.


다중 API 게이트웨이 아키텍쳐


API 게이트 웨이를 배포할때는 하나의 게이트웨이가 아니라 용도나 목적에 따라서 게이트 웨이를 분리하는 전략을 취할 수 있다. 몇가지 분리 패턴에 대해서 알아보도록 하자

내부 게이트웨이와 외부 게이트 웨이 엔드포인트 분리

가장 유용한 패턴중의 하나는 외부 서비스용 게이트웨이와 내부 서비스용 게이트웨이를 분리하는 방안이다. 물리적으로 게이트 웨이 자체를 두개로 나누는 방법도 있지만, 하나의 게이트웨이에서 엔드포인트를 내부용과 외부용으로 분리하는 방안이다.




<그림. 외부 및 내부 게이트웨이를 분리한 패턴>


같은 내부 API를 외부와 내부로 나눠서 서비스를 하되, 외부 엔드포인트에 대해서는 인증/인가 로직을 거치도록 한다.

내부 API 엔드포인트는 내부 IP를 가지도록 하고, 방화벽 안에서만 오픈하되 별도의 인증/인가 로직을 거치지 않고 내부 서버들이 API를 호출하는데 사용할 수 있도록 한다. 


파일 업/다운로드 엔드포인트 분리


API 게이트웨이는 내부 구조는 쓰레드 풀 기반의 멀티 쓰레드나 또는 비동기 IO 기반의 싱글 쓰레드 모델을 사용한다.

쓰레드 풀 모델은 톰캣같은 WAS와 비슷한 모델로, 쓰레드 풀내의 하나의 쓰레드가 하나의 API 요청에 대해서 응답까지 모두 처리하는 모델로, API 요청이 들어오면 응답을 보낼때 까지 그 쓰레드는 해당 API 호출에 의해서 점유 된다 그래서, 이러한 모델의 API 게이트웨이는 일반적인 WAS와 마찬가지로 동시에 서비스 할 수 있는 트렌젝션 수가 쓰레드풀의 전체수밖에 되지 않는다.

싱글 쓰레드 모델은 비동기 IO 기반의 방식으로 멀티 쓰레드 모델에 비해서 많은 클라이언트를 처리할 수 있다.

(비동기 IO에 대한 개념은 http://bcho.tistory.com/881 을 참고하기 바란다. Node.js가 대표적인 비동기 IO 기반의 싱글 쓰레드 모델이다.)

파일 업로드나 다운로드와 같은 트렌젝션은 CPU는 많이 사용하지 않지만, 요청 처리에 시간이 많이 걸리는 작업이기 때문에, 쓰레드 풀 형태의 API 게이트 웨이 제품에서는 파일 업/다운로드에 쓰레드가 오랫동안 잡혀있기 때문에, 서비스를 할 수 있는 유휴 쓰레드 수가 적게 되고, 다른 일반 API 서비스에 영향을 줄 수 있다.

싱글 쓰레드 기반의 비동기 IO 게이트웨이의 경우에는 비동기 IO이기 때문에 파일 업/다운로드에는 다소 유리할 수 있지만, 네트워크 대역폭을 상당 부분 소모해버리기 때문에 마찬가지로 다른 API  서비스를 하는데 영향을 줄 수 있다.

그래서 이러한 파일 업/다운로드는 가급적이면 게이트 웨이를 거치지 않고 별도의 독립된 엔드포인트나 프록시를 사용하는 것이 좋은데, 다음은 별도의 프록시를 넣는 아키텍쳐 설계 방식의 예이다.

 


<그림. 파일 업/다운로드를 API 게이트웨이에서 분리해내는 방법>


1. API 클라이언트가 파일 서버에 API를 이용하여 파일 다운로드를 요청한다.

2. 파일 서버는 API에 대한 응답으로 파일을 바로 내리는 것이 아니라, 파일을 다운로드 받을 수 있는 URL과 함께, 임시 인증 토큰을 발급(현재 API 클라이언트에 IP 에만 유효하고, 특정시간 예를 들어 발급후 30분 이내만 사용이 가능한 토큰)하여, API 클라이언트에게 리턴한다.

3. API 클라이언트는 2에서 받은 URL로 임시 인증 토큰과 함께 파일 다운로드를 파일 다운로드 프로젝시를 통해서 요청한다.

4. 파일 다운로드 프록시는 임시 인증 토큰을 인증한 다음에, 파일 다운로드를 수행한다.


파일 다운로드 프록시는 일반적인 리버스 프록시 (HA Proxy, Nginx,Apache)등을 사용할 수 있으며 여기에 간단하게 다운로드용 임시 인증 토큰 로직을 넣으면 된다. 또는 아마존 클라우드의 CDN과 같은 서비스들도 임시 다운로드 토큰과 같은 서비스를 제공하기 때문에, CDN 사용시에도 유사하게 적용할 수 있는 아키텍쳐이다.


특수 목적 엔드포인트 분리


파일 업로드/다운로드 엔드 포인트를 분리한 것 처럼, 특수 목적의 엔드포인트는 별도의 API 게이트웨이로 분리해 내는 것이 좋다.

예를 들어 인증등이 없이 고속으로 많은 로그를 업로드 하는 엔드 포인트같은 경우, 부하량이 많기 때문에 다른 일반 API 엔드포인트에 부담을 주지 않기 위해서 분리 할 수 있다.


트렌젝션 ID 추적 패턴


MSA 아키텍쳐를 기반으로 하게 되면, 클라이언트에서 호출된, 하나의 API 요청은 API 게이트웨이와 여러개의 서버를 거쳐서 처리된 후에, 최종적으로 클라이언트에 전달된다.

만약에 중간에 에러가 났을 경우, 어떤 호출이 어떤 서버에서 에러가 났는지를 연결해서 판단해야 할 수 가 있어야 한다. 예를 들어 서버 A,B,C를 거쳐서 처리되는 호출의 경우 서버 C에서 에러가 났을때, 이 에러가 어떤 메세지에 의해서 에러가 난 것이고, 서버 A,B에서는 어떻게 처리되었는 찾으려면, 각 서버에서 나오는 로그를 해당 호출에 대한 것인지 묶을 수 있어야 한다.

하나의 API 호출을 트렌젝션이라고 정의하자, 그리고 각 트렌젝션에 ID를 부여하자. 그래서 API 호출시, HTTP Header에 이 트렌젝션 ID를 넣어서 서버간의 호출시에도 넘기면 하나의 트렌젝션을 구별할 수 있다.

여기에 추가적인 개념이 필요한데, 서버 A,B,C가 있을때, API 서버 B가 하나의 API 호출에서 동 두번 호출된다고 가정하자. 그러면 에러가 났을때 B 서버에 있는 로그중에, 이 에러가 첫번째 호출에 대한 에러인지, 두번째 호출에 대한 에러인지 어떻게 구분할까?

아래 그림을 서버 A->B로의 첫번째 호출과, 두번째 호출 모두 트렌젝션 ID가 txid:1로, 이 txid로는 구별이 불가하다.

 


<그림. 단일 트렌젝션 ID를 사용했을때 문제>

그래서 이러한 문제를 해결하기 위해서는 글로벌 트렌젝션 ID(gtxid)와, 로컬 트렌젝션 ID (ltxid)의 개념을 도입할 수 있다.

API 호출을 하나의 트렌젝션으로 정의하면 이를 글로벌 트렌젝션 gtx라고 하고, 개별 서버에 대한 호출을 로컬 트렌젝션 ltx라고 한다. 이렇게 하면 아래 그림과 같이 하나의 API호출은 gtxid로 모두 연결될 수 있고 각 서버로의 호출은 ltxid로 구분될 수 있다

※ 사실 이 개념은 2개 이상의 데이타 베이스를 통한 분산 트렌젝션을 관리하기 위한 개념으로, 글로벌 트렌젝션과 로컬 트렌젝션의 개념을 사용하는데, 그 개념을 차용한것이다.

 


<그림. 글로벌 트렌젝션과 로컬 트렌젝션 개념을 이용한 API 트렌젝션 추적 방법>


이런 글로벌 트렌젝션과 로컬 트렌젝션 개념을 API 게이트웨이와 연동하여 아키텍쳐를 설계하면 다음과 같은 모양이된다.

다음 그림을 보자.

 


<그림, gtxid,ltxid를 이용한 API 트렌젝션 추적 아키텍쳐>


API 클라이언트는 API를 호출한다. API 클라이언트는 트렌젝션 ID에 대한 개념이 없다.

API 게이트 웨이에서, HTTP 헤더를 체크해서 x-gtxid (글로벌 트렌젝션 ID)가 없으면 신규 API  호출로 판단하고 트렌젝션 ID를 생성해서 HTTP 헤더에 채워 넣는다. 로컬 트렌젝션 ID로 1로 세팅한다.

2번에서, API 서버 A가 호출을 받으면, 서버 A는 헤더를 체크하여 ltxid를 체크하고, ltxid를 하나 더 더해서, 로그 출력에 사용한다. 같은 gtxid를 이용해서 같은 API호출임을 알 수 있고, ltxid가 다르기 때문에 해당 API서버로는 다른 호출임을 구별할 수 있다.

이런식으로 서버B,C도 동일한 gtxid를 가지지만, 다른 ltxid를 갖게 된다.

각 API 서버는 이 gtxid와  ltxid로 로그를 출력하고, 중앙에서 로그를 수집해서 보면, 만약에 에러가 발생한 경우, 그 에러가 발생한 gtxid로 검색을 하면, 어떤 어떤 서버를 거쳐서 트렌젝션이 수행되었고 어떤 서버의 몇번째 호출에서 에러가 발생하였는지 쉽게 판별이 가능하다.

작은 팁중에 하나로, 자바로 API 서버를 개발할 경우 서블릿 필터를 넣어서, gtxid가 헤더로 들어오면 이 gtxid를 TheadLocal 변수에 저장하고, ltxid는 새로 생성해서 ThreadLocal 변수에 저장 해놓으면, 로그를 출력할때 ThreadLocal 변수에 있는 gtxid와 ltxid를 꺼내서 같이 출력하면 번거롭게 클래스의 메서드등으로 gtxid와 ltxid를 넘길 필요가 없다.  그리고 로그 수집은 SL4J나 Log4J와 같은 일반 로깅 프레임웍을 이용해서 gtxid와 ltxid 기반으로 로그를 출력하고 출력된 로그를 파일이 아니라 logstash를 이용해서 모아서, ElasticSearch에 저장하고, Kibana로 대쉬 보드를 만들면, 손쉽게 트렌젝션 ID기반으로 API 호출 로그 추적이 가능해진다.




저작자 표시 비영리
신고

MSA 아키텍쳐 구현을 위한 API 게이트웨이의 이해 #1

조대협 (http://bcho.tistory.com)


MSA(마이크로 서비스 아키텍쳐, 이하 MSA)와 함께 근래에 떠오르고 있는것이 API 게이트 웨이이다. API 게이트웨이는 API서버 앞단에서 모든 API 서버들의 엔드포인트를 단일화하여 묶어주고 API에 대한 인증과 인가 기능에서 부터 메세지에 따라서 여러 서버로 라우팅 하는 고급기능 까지 많은 기능을 담당할 수 있다.

API 게이트웨이의 시작은 MSA가 SOA(서비스 지향 아키텍쳐)에서 시작한것 처럼 ESB (Enterprise Service Bus)에서 부터 시작 되었다. 그래서 ESB의 대부분의 컨셉을 많이 승계했는데, ESB의 실패와 단점을 보완해서 만들어진 사상이 API 게이트웨이이다. ESB가 SOAP/XML 웹서비스 기반의 많은 기능을 가지는 구조였다면, API 게이트 웨이는 JSON/REST 기반에 최소한의 기능을 처리하는 경량화 서비스 이다. 그리고 ESB는 SOA의 사상에서 개념적으로 탄생한 솔루션이라면, API 게이트 웨이는 ESB의 실패와, MSA, REST 구현 사례를 통해서 필요에 의해서 탄생한 솔루션이기 때문에, 그 실용성이 차이가 난다.


MSA에 대한 개념은 http://bcho.tistory.com/948 를 참고하기 바라며, 이 글은 API 게이트웨이에 대한 바른 이해를 돕고, API 게이트웨이를 도입하고자 하는데 필요한 내용을 서술하고자 한다.


API 게이트웨이의 주요 기능


먼저 API 게이트웨이의 주요 기능에 대해서 알아보자


인증/인가에 관련된 기능


API 게이트웨이의 가장 기본적인 기능은 API 에 대한 인증과 인가 관련 기능이다. 인증은, API 를 호출하는 클라이언트에 대한 identity(신분)를 확인 해주는 기능이고, 인가는 클라이언트가 API를 호출할 수 있는 권한이 있는지를 확인해주는 기능이다. 

쉽게 이야기 하면 내가 페이스북 계정을 가지고 있는 사용자가 맞는지 , API 호출시 어느 권한 (일반사용자, 관리자 권한)까지 호출할 수 있는지를 판단하여 API 호출을 허가하는 기능이라고 볼 수 있다.


API 토큰 발급


인증 인가를 거칠때 마다 매번 사용자의 인가/인증 절차를 거치기는 불편하다. 사용자로 부터 매번 사용자 ID와 비밀 번호를 받기는 번거롭고, 그렇다고 사용자 ID와 비밀 번호를 저장해놓는 것은 해킹의 빌미를 제공한다.

그래서 보통 사용하는 방식이 토큰이라는 방식을 사용하는데, 사용자 인가가 끝나면, 사용자가 API를 호출할 수 있는 토큰을 발급해준다. API 서버는 이 토큰으로 사용자의 identity 와 권한을 확인한후, API 호출을 허가해준다.


API 게이트 웨이는 클라이언트를 인증한 후, 이러한 API 토큰을 생성 및 발급해주는 역할을 한다.


 

<그림. 일반적은 토큰 발급 절차>


토큰 발급을 위해서는 먼저 클라이언트를 인증해야 한다.


클라이언트를 인증하는 방법은 가장 간단하게 사용자의 id와 password를 넣는 방법에서 부터, 공인 인증서를 이용하는 방법, 지문이나 OTP (One time password) 등을 이용하는 방법등 다양한 방법이 있다. 각 보안 요건에 요구 되는 다양한 방식에 따라서 클라이언트를 인증한 후에, apitoken을 발급하게 된다.


이때, 클라이언트에 대한 인증은 직접적으로 API 게이트웨이가 하지 않고 뒷단에 있는 인증 서버가 이를 수행하는데, 간단하게는 내부 계정 관리를 위한 Active Directory, LDAP 또는 RDBMS등이 될 수 도 있으며, 외부 인증 서버로는 예를 들어서 온라인 게임 서비스에 가입할때, 페이스북 계정을 사용하는 경우, 온라인 게임 서버가 페이스북에 이 사용자의 인증을 요청하고, 페이스북이 인증을 해주면 온라인 게임서버가 apitoken을 발급해주는 흐름등을 들 수 있다.


그래서 API 게이트웨이의 중요한 기능중의 하나는 다양한 인증 서버와 연계가 가능한 것이 좋다.


이렇게 발급된 토큰을 API를 호출할 수 있는 권한 정보와 연관이 되는데, 이 권한 정보를 토큰 자체에 저장하느냐 또는 서버에 저장해놓느냐에 따라서 두 가지 종류로 나눌 수 있다.

토큰 자체가 이러한 정보를 갖는 형태를 클레임 기반의 토큰 (Claim based token)이라고 하는데, 근래에 유행하는 JWT (JSON Web Token)이나 SAML 토큰등이 이에 해당한다. 예를 들어 토큰 자체가 아래와 같은 정보를 가지고 있는 형태라고 생각하면 된다. 


{

“name”:”Terry”,

“role”:[“admmin”,”enduser”]

“org”:”petstore”

}

<그림. 클레임 기반의 토큰 예>

JWT가 이러한 형태의 토큰인데 JWT에 대한 자세한 설명은 http://bcho.tistory.com/999 와 http://bcho.tistory.com/1000 를 참고하기 바란다.

클레임 기반의 토큰이 아닌 경우, 이러한 클레임 정보를 서버에 저장해놓게 되는데, 클라이언트로는 unique한 string만을 리턴해주는 경우이다.

 


<그림. 서버에 토큰을 저장하는 경우>


이 서버 기반의 토큰이 현재 일반적으로 가장 많이 사용되는 형태인데, token에 연관되는 정보가 서버에 저장되기 때문에 안전하고, 많은 정보를 저장할 수 있으며, token에 대한 정보를 수정하기가 용이하다. 그러나 서버단에서 별도의 토큰 저장소를 유지해야 하기 때문에 구현 노력이 더 높게 든다. 토큰은 매 API 호출마다 정보를 가지고 와야 하기 때문에, DBMS와 같은 FILE IO 기반의 저장소 보다는 redis, memcached와 같이 메모리 기반의 고속 스토리지를 사용하는 것이 좋다.


클레임 기반의 토큰은 이러한 토큰 저장소가 필요 없다는 장점이 있어서 구현은 용이하지만, 토큰 자체에 클레임 정보가 들어가 있기 때문에, 토큰의 길이가 커지기 때문에 일정 양 이상의 정보를 담기가 어려우며, 한번 발급된 토큰은 변경이 어렵다. 예를 들어 role:admin으로 관리자 권한으로 발급된 토큰은 서버쪽에서 파기가 불가능하기 때문에 토큰 통제가 어렵다는 단점을 가지고 있다. 그래서, 클레임 기반의 토큰을 사용할때는 토큰의 유효기간을 둬서 반드시 강제적으로 토큰을 주기적으로 재발급 받도록 하는 것이 좋다.


엔드포인트별 API 호출 인증


Apitoken이 발급되었으면, 클라이언트는 이 apitoken을 이용하여 API를 호출하는데, 이 때 API 게이트웨이는 apitoken을 검증함으로써 API 호출을 승인할지 여부를 결정한다.

서버에 토큰 정보가 저장되는 형태의 경우 매 API 호출 마다 해당 apitoken을 가지고 연관 정보를 토큰 저장소로 부터 읽어와서 비교한후, 그 정보를 기반으로 API 호출 가능 여부를 결정한다.

 




<그림. Apitoken을 이용한 API 호출 인증>


클레임 기반의 토큰의 경우에는 이러한 작업이 없이 그냥 API 게이트 웨이에서 apitoken을 까보고, 그 안에 있는 내용을 가지고 API 호출 가능 여부를 결정한다.


이렇게 api token으로 인증을 하는 방법이 일반적인 방법이지만, 서버대 서버간의 통신은 내부 서버의 경우 별도의 인증 없이 API 를 제공하는 경우도 있고, 외부 서버와의 통신은 특정 ip 주소와 통신을 허용 하거나 높은 보안을 요구하는 경우 양방향 SSL등의 인증 방식을 사용함으로써 apitoken없이도 API 호출을 인증하는 방법도 있다..

이렇게 각각의 클라이언트나 서비스 별로 제공되는 엔드포인트에 대해서 API 인증 방식이 다르기 때문에, API 게이트웨이에서는 각 엔드 포인트 별로 다양한 형태의 인증 방식을 제공해야 한다. API 게이트를 이용하여 다양한 엔드포인트를 통해 서비스를 제공하는 방법은 뒤에서 다시 설명하도록 한다.


엔드포인트별 API 요청 인가


인증(Authentication)과 인가(Authorization)은 다른 의미를 갖는데, API를 호출 하는 것이 Terry가 맞다는 것을  확인 해주는 것을 인증이라고 한다면, 이 Terry가 이 API를 호출할 수 있는 권한이 있는 것을 확인해주는 것이 인가(Authorization)이다. 쉽게 생각하면, 일반 사용자용 API와 관리자용 API를 생각하면 이해가 쉽다.


이렇게 권한을 제어하는 방식은 여러가지가 있는데, 각 개별 권한을 토큰에 부여 하는 방식과 역할(ROLE) 기반으로  권한을 부여하는 방식이 대표적이다.


개별 권한을 토큰에 부여 하는 방식은 다양한 권한 정책을 세밀하게 관리할 수 있다는 장점을 가지고 있다.

 


<그림. 토큰에 역할을 부여하는 방식>


토큰에 제한적으로 권한을 부여할 수 있다는 장점을 가지고 있는데, 페이스북이 이런 형태의 권한 통제 모델을 사용한다. 

https://developers.facebook.com/docs/facebook-login/permissions/v2.2?locale=ko_KR

에 보면 api 토큰에 연동할 수 있는 권한 리스트들이 있는데, 페이스북의 써드파티 애플리케이션을 보면, 페이스북의 API의 권한을 일부 요청 하는 형태로 토큰에 권한을 연결한다.


그렇지만,이 방식의 경우에는 권한의 종류가 많을 경우, 관리가 어려워 지고 복잡해지기 때문에, 일반적으로 역할(ROLE)기반으로 권한을 관리 하는 방식을 많이 사용한다.


직접 권한을 토큰에 연결하는 것이 아니라, 역할이라는 개념을 두고, 역할별로 권한을 연결한 다음에, 이 역할을 토큰에 부여하는 개념이다 쉽게 이야기 하면, 관리자용 기능과 일반 사용자용 기능을 분리한 다음에, 관리자나 일반 사용자와 같은 역할(ROLE)을 토큰에 부여하는 방식이다. 이를 RBAC (Role Based Access Control)이라고 한다.


이 RBAC 기반으로 하면, 통제 해야 하는 권한의 숫자가 줄어들기 때문에, 다음과 같이 엔드포인트를 나눠서 권한 접근 제어가 가능하다. (예를 들어 총 권한이 100개가 있다고 했을때, 이를 관리자용 기능과 일반 사용자용 기능으로 나누어 버리면, 관리해야 하는 두개의 권한 집합을 나뉘어 진다.) 


이런 경우 관리자용 API 엔드포인트(/service/admin), 일반 사용자용 API 엔드포인트(/service/users) 두 개로 나눈 다음에, apitoken에 권한을 admin,user 두가지 종류로 정의한 후에, /service/admin 엔드포인트에서는 api token이 admin 권한이 있을 경우에만, 호출을 허용하도록 하면 된다. 


 

<그림. 역할(ROLE)별로 엔드포인트를 나눠서 권한 인가를 하는 구조>

API 라우팅


API 게이트웨이에서 다음으로 유용한 기능중의 하나가 API 호출을 라우팅 하는 기능이다. 같은 API라도 사용하는 서비스나 클라이언트에 따라서 다른 엔드포인트를 이용해서 서비스를 제공하거나, 데이타 센터가 여러개일때, 데이타 센터간의 라우팅등을 지원하는 기능이다. 주요 기능들을 보면 다음과 같다.


백엔드 API 서버로의 로드 밸런싱


가장 기본적인 기능으로는 로드밸런서 기능이다. API 게이트 웨이 뒷단에 다수의 API 서버가 있다고 할때, 여러개의 API 서버로 부하를 분산하는 기능이 필요하다.

 


<그림. API 게이트 웨이를 통한 API 서버로의 로드 밸런싱>


단순하게 Round Robin 방식으로 부하를 분산하는 기능뿐만 아니라, 각 서버 하드웨어에 따라 부하를 가중치를 줘서 분산하는 기능등을 고려해볼 수 있겠고, 무엇보다 중요한 기능은 API 서버가 장애가 났을때 이를 감지해서 로드 밸런싱 리스트에서 빼고, 복구 되었을때 다시 로드 밸런싱 기능에 넣는 기능들이 필요하다.


단순하게, HA Proxy와 같은 L4의 기능처럼, 뒷단의 서버가 살아 있으면 부하를 보내고 죽었으면 부하를 안보내는 기능에서 부터, 고급 기능으로는 API 서버가 Hang up (멈춤)에 걸렸을 때 이를 인지해서 부하를 안보내는 기능등을 고려해볼 수 있다. 이러한 고급 기능은 API 서버의 애플리케이션 상태를 인지해야 하기 때문에 단순히 IP 포트가 살아 있음을 가지고 판단 하는 것이 아니라 쓰레드 수, 응답 시간등으로  서버의 장애 상태를 판단해야 한다.  


서비스 및 클라이언트 별 엔드포인트 제공


또 다른 유용한 기능중의 하나는, 같은 API를 여러개의 엔드포인트를 통해서 서비스를 제공할 수있다는 점인데, 하나의 시스템이 다양한 서비스나, 다양한 클라이언트등으로 서비스를 제공할때, 각각 다른 서비스 별 또는 클라이언트 별로 다른 엔드포인트를 제공할 수 있다.

예를 들어서 IOT 플랫폼 서비스가 있다고 하자. 이 플랫폼은 REST API를 제공하는데, 이를 통해서 센서로 부터 데이타를 수집해서 분석하는 시스템이라고 가정하자.

이 시스템은 선박용 서비스, 비행기용 서비스, 차량용 서비스를 지원한다고 가정하자.

각 서비스별로 API의 특성이나 노출되는 API가 다소 다를 수 있는데, 각 서비스 별로

  • 선박용 /ships/
  • 비행기용 /airplanes/
  • 차량용 /cars/

라는 식으로 각각의 다른 엔드 포인트를 제공할 수 있다.

그리고, 이 서비스에서는 센서로 부터 데이타를 수집하는 시나리오와, 관리자가 웹을 통해서 시스템을 관리하기 위한 API가 있다고 가정하면, 앞의 API는 다음과 같이 클라이언트의 종류에 따라서 분리 될 수 있다.


  • 선박 센서용 /ships/sensors/, 선박 관리자 웹 /ships/admin
  • 비행기 센서용 /airplanes/sensors/, 비행기 관리자용 /airplanes/admin
  • 차량 센서용 /cars/sensors, 차량 관리자용 /cars/admin

그리고 각각의 엔드포인트 별로 노출(expose)하는 API를 다르게 할 수 있다.

 


< 그림. API를 엔드포인트 별로 다르게 노출>


API 게이트 웨이는 API 서버가 공통적인 API를 가지더라도, 각 서비스나 클라이언트 타입에 따라서 각각 다른 API 를 선별적으로 서비스 할 수 있도록 해준다.


※ 실제로 멀티 서비스를 제공하는 플랫폼형태의 경우에는 이 기능이 매우 유용하다.특히 같은 API라도 클라이언트의 종류에 따라서 인증 방식이 다를 수 있고 보안 메커니즘이 다를 수 있다.


메세지 또는 헤더기반 라우팅


라우팅에서 유용한 기능중의 하나는 메세지 내용을 기반으로 하는 라우팅이다. 예를 들어 그림과같이 HTTP 헤더에 country code가 있을 경우, country code에 따라서 유럽에 있는 API를 호출하거나 또는 미국에 있는 API 서버를 호출할 수 있도록 Routing을 할 수 있다.

 


<그림. 메세지 기반의 글로벌 라우팅 예시>


특히 글로벌 단위로 배포되는 시스템인 경우 각 데이타 센터간에 메세지를 라우팅 시키는데 유용하게 사용할 수 있다. 위의 예에서 처럼, 특정 데이타 센터로 조건에 따라 라우팅을 할 수 도 있고, 또는 중앙 집중형 시스템의 경우, 각 지역에 API 게이트 웨이를 두고, 클라이언트는 가까운 API  게이트 웨이를 호출하지만, 중앙 데이타 센터에만 있는 API 서버의 경우 중앙 데이타 센터로 호출을 라우팅 할 수 있다.


데이타 복제가 필요할 경우, 미국에 있는 API 게이트웨이로 호출하면 API 게이트 웨이가 미국 API서버와, 유럽 API 서버를 동시에 호출해서, 업데이트성 트렌젝션을 모든 데이타 센터에 복제함으로써 API를 통한 데이타 복제가 가능해진다.

라우팅에 있어서 고려해야할 사항은 먼저 메세지에 대한 라우팅인데, REST API를 기준으로 설명하면, REST API는 HTTP URL,HTTP Header,HTTP Body 3가지로 구분이 된다.


메세지를 기반으로 라우팅을 하기 위해서는 API 게이트 웨이가 이 메세지를 파싱해야 한다.

예를 들어 country_code가 HTTP Body에 JSON으로 다음과 같이 들어가 있다고 가정하자


{

“country_code”:”US”

  :

}


이 경우 이 API 호출에 대해서 라우팅 정보를 추출하기 위해서 매번 HTTP Body에 있는 JSON을 API 게이트웨이가 파싱해서 열어봐야 한다. 이는 빠르게 메세지가 통과해야 하는 API 게이트웨이의 역할에 많은 부담을 준다. 만약에 이러한 라우팅 정보를 HTTP Header로 옮긴다면, HTTP Body는 파싱하지 않고, Header만 파싱한후, Body 정보는 라우팅되는 서버로 그냥 포워딩만 해도 된다.


그래서 메세지 기반의 라우팅을 사용할 때는 이러한 파싱에 대한 오버헤드를 잘 고려하고, 가능하면, HTTP URL이나 HTTP Header에 라우팅 필드를 넣는 것이 좋다. 


부득이하게, HTTP Body에 있는 내용으로 라우팅을 해야 하는 경우에는 호출 빈도가 적은 API인 경우 API 게이트웨이에서 담당하고, 다른 경우에는 별도의 게이트웨이 인스턴스(프로세스)로 분리를 하거나 뒷단의 API서버가 라우팅을 하도록 하는 것도 하나의 방안이 된다.


공통 로직 처리


API 게이트웨이는 특성상 모든 API 서버 앞쪽에 위치 하기 때문에, 모든 API 호출이 이 API 게이트를 거쳐간다. 그렇기 때문에, 모든 API 가 공통적으로 처리해야 하는 공통 기능이 필요할 경우 이러한 공통 기능을 API 게이트웨이로 옮기게 되면 별도로 API 서버에서 이러한 기능을 개발할 필요 없이 비지니스 로직 자체 구현에만 집중할 수 있게 된다.

아래 그림은 각 API 서버에서 인증과, 로깅에 관련된 로직을 API 게이트웨이로 이전한 구조이다.

API 로깅이나 인증은 전체 시스템에 대해 공통된 기능으로, 공통 계층에서 처리하게 되면 개발 중복을 줄일 수 있는 장점뿐만 아니라, 표준 준수가 더 쉽다는 장점을 가지고 있다. 

 


<그림 API 게이트웨이를 이용하여 공통 로직을 API 서버에서 API 게이트웨이로 이전한 구조>


메디에이션 기능 (Mediation)


메디에이션이란, 한글로 “중재”또는 “조정” 이라는 의미를 갖는데, API서버에서 제공되는 API가 클라이언트가 원하는 API 형태와 다를때, API 게이트웨이가 이를 변경해주는 기능을 이야기 한다. 구체적인 기능을 보자


메세지 포맷 변환 (Message format transformation)


메세지 포맷을 변환하는 기능이란, JSON으로 된 요청(Request) 메세지가 들어왔을때, 이를 API 서버로 보낼때 변환 해서 보내거나, 또는 API 서버에서 생성된 응답을 클라이언트에 리턴할때 변경해서 보내는 기능을 의미한다.


예를 들어보자, 아래와 같이 terry의 연봉(salary) 정보를 구하는 API가 필요하다고 하자. 그런데, 시스템에는 연봉 정보만 주는 API는 없고, 전체 사용자 정보를 리턴하는 API만 있는 상황이다.


이런 경우, API 게이트 웨이를 통해서 /users/salary라는 새로운 API를 제공하고, 이를 기존에 전체 사용자 정보를 주는 /users/details라는 API로 라우팅 한다. /users/details에서 사용자 정보를 뽑았을때, 클라이언트에게 응답을 줄때는 API 게이트웨이에서 아래 그림과 같이 name과 salary 정보만 뽑아서 리턴하도록 한다.

 


<그림. 메세지 포맷 변환의 예시>


일단 간단한 기능으로 구현이 가능하기 때문에 서술은 해놨지만, 그다지 권장하고 싶지 않은 기능이다. 메세지 포맷이 변환이 된다면, 차라리 필요한 포맷에 맞는 API를 따로 뽑아 내는 것이 났지 않나 싶다.


프로토콜 변환 


다양한 서비스나 클라이언트를 지원하게 되면, 클라이언트나 서비스별로 다른 통신 프로토콜을 사용해야 하는 경우가 있다. 웹에서는 JSON기반의 REST가 많이 사용되지만, 배나 비행기에 사용되는 센서들의 경우에는 REST도 무겁기 때문에 바이너리 기반의 경량 프토토콜을 사용하거나, 또는 예전 엔터프라이즈 시스템의 경우 XML 기반의 웹서비스를 이용할 수 도 있다.


이렇게 다양한 타입의 프로토콜을 지원하기 위해서, 각 서비스들이 새롭게 구현을 하는 것이 아니라 API 게이트웨이 계층에서 프로토콜 변환을 통하여, 같은 API를 다른 프로토콜로 서비스 할 수 있도록 할 수 있다.

 


<그림. API 게이트 웨이를 통한 프로토콜 변환>


실제로 유용한 기능인데, 내부 API는 REST가 아니라 페이스북 Thrift나 구글의 Protocol Buffer로 구현을 하고, 외부에 제공하는 API는 API 게이트 웨이단에서 REST 로 변경해서 서비스 하는 구조를 이용하면, 내부 API 성능을 올리고, 외부로는 REST API로 서비스 함으로써 범용성을 확보할 수 있다. (실제 사례가 있었다.)


또한 근래에 M2M이나 IOT (Internet of things)와 같은 개념이 활성화 되면서, HTTP REST 뿐 아니라 기존의 센서에서 통신에 사용되는 다양한 프로토콜을 지원하여 백엔드 API 서버의 프로토콜로 맞춰줘야 하는 필요가 점점 증대되고 있다.


메세지 호출 패턴 변환 (Message Exchange Pattern : MEP)


메세지 호출 패턴, 보통 MEP(Message Exchange Pattern)라고 하는데, 동기,비동기 호출과 같은 API를 호출하는 메세지 패턴을 정의한다.

API 게이트웨이의 좋은 기능중의 하나가 이 MEP를 변경할 수 있다는 건데, 쉽게는 Async API호출을 Sync 호출로 바꿔 준다거나, 하나의 API 호출을 여러 데이타 센터로 복제 해준다거나 하는 형태의 메세징 패턴을 변화 시킬 수 있다.

 


<그림. 비동기 호출을 API게이트웨이를 통해서, 동기 호출로 변경한 구조>


위의 그림의 예제는 로그를 수집하는 시스템에 대한 구조이다.뒷단의 로그저장 API 서버가 대용량 트래픽에 대한 대응 능력이 없을때, API 게이트 웨이에서 큐를 이용해서 API 요청을 받고 (1), 바로 클라이언트에 ACK를 준후에, 메세지큐 연동을 이용하여 메세지를 저장한후, 로그 저장 API 서버의 성능에 맞게 흘려주는 방식이다. 클라이언트 입장에서는 동기 호출이지만 실제 메세지 흐름은 큐를 이용한 비동기 구조로 변경되었다.


어그레게이션 (aggregation)


SOA에서는 Orchestration(오케스트레이션)이라고 불렀는데, 여러개의 API를 묶어서 하나의 API로 만드는 작업을 이야기 한다. 예를 들어서, 계좌 이체를 한다고 했을때,


A은행에서 잔액 확인

A은행에서 인출

B은행으로 입금


하는 3개의 API 호출을 하나의 API 인 POST transfer(인출계좌,입급계좌,금액)으로 구현한다고 하자.이를 API 게이트웨이에서 구현 하면 다음과 같은 형태로 구현할 수 있다.

 


<그림. API 게이트 웨이를 이용한 API Aggregation>


대부분의 API 게이트 웨이 제품들은 이러한 aggregation을 할 수 있는 일종의 워크플로우 엔진과 유사한 기능들을 가지고 있다.


 


<그림. Apigee 제품의 워크플로우 저작도구 화면>


이러한 aggregation 기능이 언뜻 보면 좋아보이지만, 하나의 플로우에서, 여러 API를 호출해야 하고, 비지니스 로직을 수행하면서 실제로 API 메세지 BODY까지 파싱해야 하기 때문에, API 게이트 웨이 입장에서는 부하가 매우 크다. 


MSA 의 전신인 SOA에서 API 게이트웨이와 유사한 역할을 했던 ESB역시 이러한 aggregation (ESB에서는 보통 오케스트레이셔이라고 함)을 남발해서, ESB의 성능이 떨어져서 시스템 개발이 실패하는 아키텍쳐를 많이 봤다.

그래서 본인의 경우에는 이러한 무거운 aggregation 로직은 별도의 Mediator API 서버라는 계층을 만들어서, API 게이트웨이 밖에서 따로 하는 방법을 권장한다.


아래 그림과 같이 여러 API를 조합하는 목적의 API 서버를 별도로 둬서, 이러한 기능을 API 게이트웨이에서 제거한다.

 


<그림. API aggregation을 API 게이트웨이에서 Mediation API 서버로 분리한 구조>


aggregation 로직을 API 게이트웨이 안에 넣으면 확실하게  게이트웨이가 받는 부하량은 올라간다. 설치형 API 게이트웨이의 경우, 이는 추가적인 하드웨어 박스를 더 구매하고, 상용 API 게이트웨이의 경우 라이센스를 더 구매해야 한다는 것을 의미하기 때문에, Mediation API 서버 계층을 사용하는 것을 권장한다.


클라우드형 API 게이트웨이의 경우, 호출 수로 과금을 하기 때문에 aggregation 로직을 API 게이트웨이에 넣는 방안을 고려해볼 수 있으나, aggregation 로직이 게이트웨이 안에 있으면 디버깅이나 테스팅이 쉽지 않기 때문에, 이를 적절히 고민한 후 판단해서 aggregation 로직의 위치를 결정해야 한다.


로깅 및 미터링


API 게이트웨이의 비기능적인 요건으로 중요한 기능이 로깅과 미터링이다. 


API 호출 로깅


앞서 공통 로직 처리 부분에서도 언급하였지만, API 호출시 API 게이트웨이는 공통적으로 호출되는 부분인 만큼 모든 로그를 중간에서 수집하기가 가장좋다.


근래의 애플리케이션 아키텍쳐가 클라이언트와 서버간의 통신이 모두 API를 기반하는 형태로 변경이되어감에 따라 API 호출 패턴을 분석하면 사용자의 사용 패턴을 분석해낼 수 있기 때문에, 빅데이타 영역과 연계하여 API 호출 로그는 아주 중요한 자산으로 다루어지고 있다.


또한 API 호출 로그는 차후 문제가 발생하였을때, 문제를 추적하기 위한 중요한 자료로 사용된다. (Audit: ‘감사’의 목적) 그래서, API 로그 수집은 단순 분석 목적뿐 아니라, 향후 감사 목적용으로도 저장되어야 한다.


근래에 출시되고 서비스되는 클라우드형 API 게이트웨이의 경우에는 특히나 이 API에 대한 로그 분석 기능을 강화해서 출시되고 있다.

 


<그림. Apigee.com의 API 모니터링>


API 미터링 & 차징 (Metering & Charing)


API 미터링과 차징은 유료 API 서비스를 위한 기능으로,  미터링은 과금을 위한 API 호출 횟수,클라이언트 IP, API 종류,IN/OUT 용량등을 측정 기록하는 서비스이고,

차징은 미터링이 된 자료를 기반으로 하여, API 서비스 사용 금액을 금액 정책에 따라서 계산 해내는 서비스이다. 

대부분의 SNS 오픈 API 서비스는 무료인 경우가 많지만, 구글 API 의 경우에도, 특정 호출 횟수(/일)을 넘어가면 과금등을 하도록 되어 있다.


QoS 조정 (Quality of service)


마지막으로 QoS 조정 기능이란, API 서비스를 클라이언트 대상에 따라서 서비스 레벨을 조정하는 기능이다.

유료 서비스가 있는  API 서비스라고 가정할때, 무료 사용자의 경우 1일 1000건으로 호출횟수를 제한 한다거나, 전송 용량이나, 네트워크 대역폭을 유료/무료 사용자에 따라 다르게 적용하는 것과 같은 기능을 QoS 기능이라고 한다.

유료 서비스인 경우만 아니라, 플랫폼 차원에서 다양한 클라이언트나 다양한 서비스로 API 를 제공하는 경우, 각 클라이언트나 서비스에 따라서 이 QoS를 조정하는 기능은 유용하게 사용될 수 있다. 특정 서비스나 클라이언트가 폭주하여 API를 과도하게 사용하여 다른 서비스들이 API를 사용할 수 없게 한다던가 그런 문제를 미연에 예방할 수 있다.


결론


지금까지 간단하게나마 API 게이트웨이의 대략적인 기능에 대해서 알아보았다. 다음에는 API 게이트웨이 기반 아키텍쳐를 확장하는 방법과 API 게이트웨이의 안티패턴과 설계 방법론 등에 대해서 소개하도록 한다.


참고

API 플랫폼의 이해 http://bcho.tistory.com/808

대용량 분산 시스템을 위한 마이크로서비스 아키텍쳐 http://bcho.tistory.com/948




저작자 표시 비영리
신고

JWT(JSON Web Token)을 이용한 API 인증 - #1 개념 소개

조대협 (http://bcho.tistory.com)


REST API에 대한 보안과 인증이 화두가 되면서 많이 언급되는 것이 OAuth인데, 근래에 들어서 화두가 되고 있는 것이 JWT (JSON Web Token)이라는 표준이다.


Claim기반 토큰의 개념


OAuth에 의해서 발급되는 access_token은 random string으로 토큰 자체에는 특별한 정보를 가지고 있지 않는 일반적인 스트링 형태 이다. 아래는 페이스북에서 발급된 access_token의 형태로 일반적인 문자열 형태임을 확인할 수 있다.



<그림1.  Facebook의 Oauth에서 사용하는 일반적인 스트링 기반 토큰 예제>

 

 API나 서비스를 제공하는 서버 입장에서 그 access_token을 통해서 사용자에 연관된 권한(예를 들어 scope같은 것)을 식별한 뒤 권한을 허용해주는 구조이다.

즉 서비스를 제공하는 입장에서는 토큰을 가지고 그 토큰과 연관된 정보를 서버쪽에서 찾아야 한다. (사용자 ID나 권한등).

JWT는 Claim 기반이라는 방식을 사용하는데, Claim이라는 사용자에 대한 프로퍼티나 속성을 이야기 한다. 토큰자체가 정보를 가지고 있는 방식인데, JWT는 이 Claim을 JSON을 이용해서 정의한다.

다음은 Claim을 JSON으로 서술한 예이다.이 JSON 자체를 토큰으로 사용하는 것이 Claim 기반의 토큰 방식이다.

{

  "id":"terry"

  ,"role":["admin","user"]

  ,"company":"pepsi"

}

<코드 1. JSON으로 Claim을 기술한 토큰의 형태 >

자 그렇다면, 이러한 Claim 방식의 토큰은 무엇이 좋을까? 이 토큰을 이용해서 요청을 받는 서버나 서비스 입장에서는 이 서비스를 호출한 사용자에 대한 추가 정보는 이미 토큰안에 다 들어가 있기 때문에 다른 곳에서 가져올 필요가 없다는 것이다.

“사용자 관리” 라는 API 서비스가 있다고 가정하다.

 이 API는 “관리자(admin)” 권한을 가지고 있는 사용자만이 접근이 가능하며, “관리자” 권한을 가지고 있는 사용자는 그 관리자가 속해 있는 “회사(company)”의 사용자 정보만 관리할 수 있다. 라고 정의하자

이  시나리오에 대해서 일반적인 스트링 기반의 토큰과 JWT와 같은 Claim 기반의 토큰이 어떤 차이를 가질 수 있는 지 알아보도록 하자.


OAuth 토큰의 경우



<그림 2. String 토큰에 의한 API 권한 인증 흐름>

 

1.    API 클라이언트가 Authorization Server (토큰 발급서버)로 토큰을 요청한다.

이때, 토큰 발급을 요청하는 사용자의 계정과 비밀번호를 넘기고, 이와 함께 토큰의 권한(용도)을 요청한다. 여기서는 일반 사용자 권한(enduser)과 관리자 권한(admin)을 같이 요청하였다.

2.    토큰 생성 요청을 받은 Authorization Server는 사용자 계정을 확인한 후, 이 사용자에게 요청된 권한을 부여해도 되는지 계정 시스템등에 물어본 후, 사용자에게 해당 토큰을 발급이 가능하면 토큰을 발급하고, 토큰에 대한 정보를 내부(토큰 저장소)에 저장해놓는다.

3.    이렇게 생성된 토큰은 API 클라이언트로 저장된다.

4.    API 클라이언트는 API를 호출할때 이 토큰을 이용해서 Resource Server(API 서버)에 있는 API를 호출한다.

5.    이때 호출되는 API는 관리자 권한을 가지고 있어야 사용할 수 있기 때문에, Resource Server가 토큰 저장소에서 토큰에 관련된 사용자 계정, 권한 등의 정보를 가지고 온다. 이 토큰에 (관리자)admin 권한이 부여되어 있기 때문에, API 호출을 허용한다. 위에 정의한 시나리오에서는 그 사용자가 속한 “회사”의 사용자 정보만 조회할 수 있다. 라는 전제 조건을 가지고 있기 때문에, API 서버는 추가로 사용자 데이타 베이스에서 이 사용자가 속한 “회사” 정보를 찾아와야한다.

6.    API서버는 응답을 보낸다.


JWT와 같은 Claim 기반의 토큰 흐름을 보자

 



<그림 3. Claim 기반의 토큰을 이용한 API 권한 인증 흐름 >

 

1.    토큰을 생성 요청하는 방식은 동일하다.  마찬가지로 사용자를 인증한다음에, 토큰을 생성한다.

2.    다른 점은 생성된 토큰에 관련된 정보를 별도로 저장하지 않는다는 것이다. 토큰에 연관되는 사용자 정보나 권한등을 토큰 자체에 넣어서 저장한다.

3.    API를 호출하는 방식도 동일하다.

4.    Resource Server (API 서버)는 토큰 내에 들어 있는 사용자 정보를 가지고 권한 인가 처리를 하고 결과를 리턴한다.

결과적으로 차이점은 토큰을 생성하는 단계에서는 생성된 토큰을 별도로 서버에서 유지할 필요가 없으며

토큰을 사용하는 API 서버 입장에서는 API 요청을 검증하기 위해서 토큰을 가지고 사용자 정보를 별도로 계정 시스템 등에서 조회할 필요가 없다는 것이다.


참고 : 다른 Claim 기반 토큰은?


그러면 이러한 Claim 기반의 토큰이 JSON이 처음일까? 이미 이전에, XML기반의 SAML 2.0이 이와 비슷한 개념을 가지고 있다. Assertion이라는 개념으로 XML안에 이러한 Claim 정보를 넣어서 넘길 수 있었으나, 문제점은 전체적인 사이즈가 너무 크고, 구조가 복잡하여 쉽게 접근이 어려웠다. 더군다가 크기가 크기 때문에 API와 같이 자주 호출해야 하는 경우에는 HTTP 헤더등에 실어서 보내기가 어렵고, 파싱에 대한 오버해드가 크기 때문에 적절하지 않았다. (주로 다른 사이트나 시스템간의 SSO에서 상호 사용자 인증등을 위해서 사용된다. 무겁기는 하지만 표준화가 잘되어 있기 때문에 사용자 인증 시나리오에서는 현재에도 많이 사용된다.)

JWT는 이JSON Claim을 BASE64로 인코딩하여HTTP Header에 쉽게 넣을 수 있으며, JSON 기반이기 때문에 파싱과 사용이 쉽다.

결과적으로 Claim 기반의 토큰은 토큰 자체가 정보를 담음으로써, 토큰을 가지고 서비스나 API 접근을 제어할 때 별도의 작업이 서버에서 필요하지 않으며, 토큰 자체를 서버에서 관리할 필요가 없기 때문에 구현이 상대적으로 단순해진다.


JWT에 대한 소개


Claim 기반의 토큰에 대한 개념을 대략적으로 이해했다면, 그러면 실제로 JWT가 어떻게 구성되는지에 대해서 살펴보도록 하자.


Claim (메세지) 정의

JWT는 Claim을 JSON형태로 표현하는 것인데, JSON은 “\n”등 개행문자가 있기 때문에, REST API 호출시 HTTP Header등에 넣기가 매우 불편하다. 그래서, JWT에서는 이 Claim JSON 문자열을 BASE64 인코딩을 통해서 하나의 문자열로 변환한다.

{

  "id":"terry"

  ,"role":["admin","user"]

  ,"company":"pepsi"

}

<코드 2. JSON 기반의Claim 예제>

문자열을 BASE64 인코딩 한 결과

ew0KICAiaWQiOiJ0ZXJyeSINCiAgLCJyb2xlIjpbImFkbWluIiwidXNlciJdDQogICwiY29tcGFueSI6InBlcHNpIg0KfQ0K

<코드 3. JSON 기반의 Claim 코드 2를 BASE64 인코딩 한 결과>


변조 방지

위의 Claim 기반의 토큰을 봤으면, 첫번째 들 수 있는 의문이 토큰을 받은 다음에 누군가 토큰을 변조해서 사용한다면 어떻게 막느냐? 이다. 이렇게 메세지가 변조 되지 않았음을 증명하는 것을 무결성(Integrity)라고 하는데, 무결성을 보장하는 방법중 많이 사용되는 방법이 서명(Signature)이나 HMAC 사용하는 방식이다. 즉 원본 메세지에서 해쉬값을 추출한 후, 이를 비밀 키를 이용해서 복호화 시켜서 토큰의 뒤에 붙인다. 이게 HMAC방식인데,  누군가 이 메세지를 변조를 했다면,변조된 메세지에서 생성한 해쉬값과 토큰뒤에 붙어 있는 HMAC값이 다르기 때문에 메세지가 변조되었음을 알 수 있다. 다른 누군가가 메세지를 변조한후에, 새롭게 HMAC값을 만들어내려고 하더라도, HAMC은 앞의 비밀키를 이용해서 복호화 되었기 때문에, 이 비밀키를 알 수 없는 이상 HMAC을 만들어 낼 수 없다.


※ HMAC에 대한 자세한 설명은http://bcho.tistory.com/807 를 참고하기 바란다.

그래서 앞의 JSON 메세지에 대해서 SHA-256이라는 알고리즘을 이용해서 비밀키를 “secret” 이라고 하고, HMAC을 생성하면 결과는 다음과 같다.

i22mRxfSB5gt0rLbtrogxbKj5aZmpYh7lA82HO1Di0E

<코드 4. 코드 2의 JSON기반 Claim에 대해서, SHA1-256으로 생성한 HMAC>

서명 생성 방식

그러면 무결성 보장을 위해서 사용할 수 있는 알고리즘이 SHA1-256 HMAC 뿐일까? 보안요건에 따라서 SHA1-256,384,512. 그리고 공인 인증서 (Ceritification)을 이용한 RS256 등등 다양한 서명 방식을 지원한다. 그렇다면 JWT 토큰이 어떤 방식으로 서명이 되어 있는지는 어떻게 알 수 있을까?

그래서 JWT 토큰의 맨 앞부분에는 서명에 어떤 알고리즘을 사용했는지를 JSON형태로 정의한후, 이 JSON을 다시 BASE64 방식으로 인코딩한 문자열을 붙인다

{"alg":"HS256","typ":"JWT"}

<코드 5. JSON으로 서명 생성 방식은 SHA1-256으로 정의한 예>

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

<코드 6. 위의 코드 5 JSON 문자열을 BASE64 인코딩한 결과>

 

전체 메세지 포맷


위에서 설명한, 서명 방식, JSON 기반의 Claim,그리고 서명(Signature)까지 포함된 전체적인 JWT 토큰의 구조를 보면 다음과 같다.

{서명 방식을 정의한 JSON을 BASE64 인코딩}.{JSON Claim을 BASE64 인코딩}.{JSON Claim에 대한 서명}

이를 정리해서 그림으로 서술해 보면 다음과 같다.


<그림. JWT 토큰 구조>

그리고 결과로 나온, JWT 토큰은

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ew0KICAiaWQiOiJ0ZXJyeSINCiAgLCJyb2xlIjpbImFkbWluIiwidXNlciJdDQogICwiY29tcGFueSI6InBlcHNpIg0KfQ0K.i22mRxfSB5gt0rLbtrogxbKj5aZmpYh7lA82HO1Di0E

가 된다.


2편에서 다룰 내용

  • 유출 방지(암호화)

  • 상세 스펙

  • 구현예제


 

 

 

 

저작자 표시 비영리
신고

서버와 APNS(애플푸쉬서버)와의 보안 메커니즘 


애플 iOS 디바이스로 서버가 푸쉬를 보내고자 할때는, APNS 서비스를 거쳐야 한다.

푸쉬 메시지를 보내고자 하는 Provider 서버가 APNS로 푸쉬 요청을 보내면, APNS 서버가 디바이스로 푸쉬를 보내는 구조이다.

이때 APNS 서버와 Provider 서버를 어떻게 신뢰하는 지를 알아보자.

APNS 서버 입장에서는 Provider 서버가 해커가 아냐? 진짜 Provider 맞아? 하는 의문을 가질 수 있고, Provider 서버도 APNS 서버가 진짜 APNS 서버가 맞는지를 확인할 수 있어야 한다.

이를 양방향 SSL(TLS:Transport Level Security)를 이용해서 해결 한다.

먼저 SSL 메커니즘에 대해서 알아보자 SSL 을 비대칭 (PKI) 키 구조의 암호화를 이용하는데, Public Key Private Key 두개를 가지고 있다. Public Key로 암호화를 할 수 있지만, 반대로 암호를 푸는 복호화는 Private Key를 통해서만 가능하다.

그래서 서버가 SSL 연결을 보낼 때, Public Key를 클라이언트에 내려 보내면, 클라이언트는 그 Public Key를 사용해서 메시지를 암호화 해서 서버에 전송하고, Private Key를 가지고 있는 서버만이 그 메시지를 해석할 수 있는 구조이다.


Main In The Middle attack

그런데 이 과정에서 취약점이 발생하는데, 서버가 Public Key를 내려보낼 때 중간에 해커가 서버서부터 온 Public Key를 낚아채고, 자신이 새로운 Public Key A1 Private Key A2 페어를 만든 후, 새롭게 만든 Public Key A1을 클라이언트로 내려보낸다. 그러면 클라이언트는 이 Public Key A1을 가지고 암호화를 해서 중간에 해커에게 보내고, 해커는 이 메시지를 자신의 Private Key A2로 열어서 본후에, 다시 원래 서버가 준 Public Key로 메시지를 암호화 해서 서버에 보낸다.

이 때 클라이언트와 서버는 Public Key Private Key로 안전하게 통신하는 것 처럼 보이지만, 사실은 사실은 중간에 해커에 의해서 메시지가 도청되고 있는 상황이 된다. 이런 Attack 방식을 Man In The Middle attack (MITM)


Signing

이러한 Public Key가로채기를 막을려면 Public Key를 받는 클라이언트 쪽에서 이 Public Key APNS에서 온 것이 맞는지를 확인하면 되는데, 보통 이 Public Key는 인증서(Certificate)안에 넣어서 클라이언트에게로 배달된다. 이 때 메시지 변조를 막기 위해서 Certificate는 안에 들어 있는 메시지로 생성된 일종의 해쉬값과 같은 signature 값을 가지고 있어서, 만약에 내부 메시지가 변경이 되면 원래 signature와 비교하여 메시지가 변경되었는지를 확인할 수 있다.이를 생성하는 것을 싸이닝(Signing) 이라고 하는데, Signing Private 키로 생성되고, 이에 대한 비교는 Public Key를 통해서 할 수 있다. (Sign을 확인하기 위해서는 Sign에 사용된 Private Key에 대한 페어 Public Key를 가진 인증서를 가지고 있어야 한다. Public Key를 통해서 싸이닝을 확인할 수 있다.)




Channing

signature를 통해서 전달되는 메시지가 변조되는 것을 막을 수 는 있지만 위의 MITM attack 처럼 인증서 자체를 통째로 바꿔칠 수 있기 때문에, 이 인증서가 믿을만한 인증서인지를 확인해야 한다. 인증서에는 인증서를 발급한 기관 (CA : Certificate Authority)정보가 들어 있는데, “XXX에서 인증서를 발급함이라는 정보가 들어 있다.

그런데 문제는 이 인증서를 발급한 기관을 믿을 수 있냐는 거다. 구멍가게가 될 수 도 있고

은행과 같은 인증된 기관이 될 수 도 있다. 그래서 사용하는 기법에 인증서 Channing 기법인데, 인증서를 발급한 사람이 이 인증서를 신뢰된 기관에 가서 인증을 받은 후, 그 인증 정보를 인증서에 추가하는 방식이다.

아래 그림을 보자, 맨 아래의 Engineering CA는 자체 적으로 인증서를 발급하였다. 이 인증서를 USA CA certificate에 보내서 추가 인증을 받는다. 그런데, USA CA certificate 인증서는 이미 신뢰된 기관으로부터 인증을 받은 인증서이기 때문에, 이 신뢰된 기관의 인증 정보가 추가되게 된다. (신뢰된 인증 기관으로부터 인증서에 서명을 받으려면 회사 정보,신상 정보 등을 받은 후에 신원 확인 절차를 거쳐야만이 서명을 받을 수 있다.)



(출처 : https://developer.mozilla.org/en-US/docs/Introduction_to_Public-Key_Cryptography)

그래서 최종 인증서 모양은



이러한 형태가 되고, 클라이언트는 이 인증서 chain을 통해서 Root CA가 신뢰된 인증서인지를 확인하면 이 전체 인증서가 신뢰된 인증서임을 확인할 수 있다. (네트워크를 통해서 Root CA가 맞는지를 확인하게 되고, 만약에 Root CA라도 외부로 노출이 되었을 경우에 Revoked List라는 유출된 인증서 목록을 유지함으로써 인증서가 문제가 없는 인증서인지를 확인할 수 있다.)

이러한 절차를 거치면 MITM Attack을 통한 감청을 막을 수 있다.

다음 문제는 클라이언트 입장에서는 서버가 신뢰할 수 있는 서버인지를 알 수 있다. (Provider는 이 Root CA를 통해서 서버가 APNS 서버임을 알 수 있다.)


Mutual SSL

그러나 서버 입장에서는 클라이언트가 Provider서버가 맞는지? 를 확인할 필요가 있다. 이것이 인증 (authentication) 과정인데, TLS(SSL) 연결이 안전하게 설정된 후에, 사용자 ID,PASSWD를 넣어서 클라이언트(Provider)를 확인하는 방법도 있지만, 조금 더 확실한 방법으로, 클라이언트가 발급한 인증서를 사용하는 방식을 사용한다.

이 방식이 양방향 SSL 방식 (Mutual SSL) 인데, SSL 연결이 될 때 서버가 클라이언트에게 Public Key 를 내려 보내는 방식과 마찬가지로 클라이언트가 서버에게 Public Key를 전송하고 메시지를 클라이언트의 Private Key를 이용해서 암호화 해서 보내는 방법이다.

이 때 클라이언트에서 서버로 전송하는 Public Key는 인증서를 통해서 전달이 되게 되고, 인증서에는 인증서 발급 기관등의 정보가 들어가 있기 때문에, 이를 통해서 클라이언트를 인증을 할 수 있다.


APNS CSR

그래서 APNS의 경우에는 Service Provider Private/Public Key pair 를 생성한 후에, Public Key만을 담은 인증서를 생성하여, 웹사이트를 통해서 Service Provider 업체에 대한 정보와 함께, 싸인을 요청한다.

싸인을 진행할 때 애플은 인증서에 대한 고유 ID등을 통해서 이 인증서를 통한 호출이 어느 기관(업체)에서 들어오는지를 맵핑 해놓고, 향후 양방향 SSL 연결시에 이 정보를 가지고 클라이언트를 판독할 수 있다.

이를 기반으로 전체 서버간의 플로우를 보면

1.  ProviderPrivate Key를 생성한다

2.  Private Key를 기반으로 *.csr 파일(인증서 싸인 요청 파일)을 만든다. 이 파일에는 Public key가 들어 있는 인증서와 싸이닝을 요청하는 Provider의 업체 정보들이 들어가 있다.

3.  Provider는 애플 포탈에 들어가서 이 csr 파일을 업로드 한다.

4.  애플 포탈은 csr 파일을 기반으로 인증서(certificate)를 생성한후에, 애플의 인증서를 이용해서 싸인을 추가해서 Provider에게 돌려준다.

5.  Provider 4에서 받은 인증서(public key가 들어 있는)1에서 생성된 Private KeyProvider 서버내에 설치 한다.

6.  이때 1에서 생성한 Private Key,그리고 애플이 싸이닝하여 추가된 Public Key 가 들어 있는 인증서, 인증서 체인에 사용된 모든 인증서를 추가해서 한 파일(*.p12)에 넣는다.(*.p12 파일 포맷은 X.509를 지원하는 파일 포맷중에 유일하게 Private Key를 같이 넣을 수 있는 포맷이다.)




APNS Provider간의 Trust

다음 통신이 이루어지게 되면, 아래 그림과 같이

1.  Provider ServerTLS 연결을 요청한다.

2.  APNS 서버는 certificate(인증서) public key를 넣어서 내려 보낸다.

3.  Provider는 이 인증서의 Root CA를 확인하여, 이 인증서가 애플에서 온 정상적인 인증서임을 확인한다. (Provider가 상대편이 APNS임을 확인함)

4.  Provider는 앞의 CSR에 의해 생성된 인증서를 APNS에 보낸다.

5.  APNS 4에서 온 인증서에 애플의 인증서로 Sign 이 되어 있는 것을 확인하고, 클라이언트가 (Provider) 합법적인 클라이언트임을 확인하고,어떤 사용자인지를 판독한다. (APNS Provider가 누구인지를 확인하였다.)

6.  마지막으로 양 서버간의 신뢰돈 TLS(SSL)연결이 성립되었다.



 

저작자 표시 비영리
신고

'아키텍쳐  > Security & IDM' 카테고리의 다른 글

서버와 APNS(애플푸쉬서버)와의 보안 메커니즘  (3) 2014.10.07
OAuth 2.0 노트  (0) 2014.08.11
OAuth 2.0 based API 인증 메모  (0) 2014.06.05
Digital Signing의 개념  (0) 2014.05.21
Java keystore file  (0) 2013.09.27
SSL/TLS 관련 개념 링크  (1) 2013.09.24

마이크로 서비스 아키텍쳐 (MSA의 이해)

조대협(http://bcho.tistory.com)

 

배경


마이크로 서비스 아키텍쳐(이하 MSA)는 근래의 웹기반의 분산 시스템의 디자인에 많이 반영되고 있는 아키텍쳐 스타일로, 특정 사람이 정의한 아키텍쳐가 아니라, 분산 웹 시스템의 구조가 유사한 구조로 설계 되면서, 개념적으로만 존재하던 개념이다.

얼마전 마틴파울러(Martin folwer)가 이에 대한 MSA에 대한 개념을 글로 정리하여, 개념을 정립 시키는데 일조를 하였다.

이 글에서는 대규모 분산 웹시스템의 아키텍쳐 스타일로 주목 받고 있는 MSA에 대한 개념에 대해서 알아보도록 한다.


모노리틱 아키텍쳐(Monolithic Architecture)


마이크로 서비스 아키텍쳐를 이해하려면 먼저 모노리틱 아키텍쳐 스타일에 대해서 이해해야 한다

모노리틱 아키텍쳐 스타일은 기존의 전통적인 웹 시스템 개발 스타일로, 하나의 애플리케이션 내에 모든 로직들이 모두 들어 가 있는 “통짜 구조” 이다.

예를 들어, 온라인 쇼핑몰 애플리케이션이 있을때, 톰캣 서버에서 도는 WAR 파일(웹 애플리케이션 패키징 파일)내에, 사용자 관리,상품,주문 관리 모든 컴포넌트들이 들어 있고 이를 처리하는 UX 로직까지 하나로 포장되서 들어가 있는 구조이다.




각 컴포넌트들은 상호 호출을 함수를 이용한 call-by-reference 구조를 취한다.

전체 애플리케이션을 하나로 처리하기 때문에, 개발툴 등에서 하나의 애플리케이션만 개발하면 되고, 배포 역시 간편하며 테스트도 하나의 애플리케이션만 수행하면 되기 때문에 편리하다.

문제점

그러나 이러한 모노리틱 아키텍쳐 시스템은 대형 시스템 개발시 몇가지 문제점을 갖는다.

모노리틱 구조의 경우 작은 크기의 애플리케이션에서는 용이 하지만, 규모가 큰 애플리케이션에서는 불리한 점이 많다.

크기가 크기 때문에, 빌드 및 배포 시간, 서버의 기동 시간이 오래 걸리며 (서버 기동에만 2시간까지 걸리는 사례도 경험해봤음)

프로젝트를 진행하는 관점에서도, 한두사람의 실수는 전체 시스템의 빌드 실패를 유발하기 때문에, 프로젝트가 커질 수 록, 여러 사람들이 협업 개발하기가 쉽지 않다

또한 시스템 컴포넌트들이 서로 로컬 콜 (call-by-reference)기반으로 타이트하게 연결되어 있기 때문에, 전체 시스템의 구조를 제대로 파악하지 않고 개발을 진행하면, 특정 컴포넌트나 모듈에서의 성능 문제나 장애가 다른 컴포넌트에까지 영향을 주게 되며, 이런 문제를 예방하기 위해서는 개발자가 대략적인 전체 시스템의 구조 등을 이해 해야 하는데, 시스템의 구조가 커질 수 록, 개인이 전체 시스템의 구조와 특성을 이해하는 것은 어려워진다.

특정 컴포넌트를 수정하고자 했을때, 컴포넌트 재 배포시 수정된 컴포넌트만 재 배포 하는 것이 아니라 전체 애플리케이션을 재 컴파일 하여 전체를 다시 통으로 재배포 해야하기 때문에 잦은 배포가 있는 시스템의 경우 불리하며,

컴포넌트 별로, 기능/비기능적 특성에 맞춰서 다른 기술을 도입하고자 할때 유연하지 않다. 예를 들어서, 전체 애플리케이션을 자바로 개발했다고 했을 때, 파일 업로드/다운 로드와 같이 IO 작업이 많은 컴포넌트의 경우 node.js를 사용하는 것이 좋을 수 있으나, 애플리케이션이 자바로 개발되었기 때문에 다른 기술을 집어 넣기가 매우 어렵다.

※ 모노리틱 아키텍쳐가 꼭 나쁘다는 것이 아니다. 규모가 작은 애플리케이션에서는 배포가 용이하고, 규모가 크더라도, call-by-reference call에 의해서 컴포넌트간 호출시 성능에 제약이 덜하며, 운영 관리가 용이하다. 또한 하나의 구조로 되어 있기 때문에, 트렌젝션 관리등이 용이하다는 장점이 있다. 즉 마이크로 서비스 아키텍쳐가 모든 부분에 통용되는 정답은 아니며, 상황과 필요에 따라서 마이크로 서비스 아키텍쳐나 모노리틱 아키텍쳐를 적절하게 선별 선택 또는 변형화 해서 사용할 필요가 있다.


마이크로 서비스 아키텍쳐


마이크로 서비스 아키텍쳐는 대용량 웹서비스가 많아짐에 따라 정의된 아키텍쳐인데, 그 근간은 SOA (Service Oriented Architecture : 서비스 지향 아키텍쳐)에 두고 있다.

SOA는 엔터프라이즈 시스템을 중심으로 고안된 아키텍쳐라면, 마이크로 서비스 아키텍쳐는 SOA 사상에 근간을 두고, 대용량 웹서비스 개발에 맞는 구조로 사상이 경량화 되고, 대규모 개발팀의 조직 구조에 맞도록 변형된 아키텍쳐이다.


아키텍쳐 구조


서비스


마이크로 서비스 아키텍쳐에서는 각 컴포넌트를 서비스라는 개념으로 정의한다. 서비스는 데이타에서 부터 비지니스 로직까지 독립적으로 상호 컴포넌트간의 의존성이 없이 개발된 컴포넌트(이를 버티컬 슬라이싱/Vertical Slicing-수직적 분할이라고 한다.)로 REST API와 같은 표준 인터페이스로 그 기능을 외부로 제공한다.

서비스 경계는 구문 또는 도메인(업무)의 경계를 따른다. 예를 들어 사용자 관리, 상품 관리, 주문 관리와 같은 각 업무 별로 서비스를 나눠서 정의한다. 사용자/상품 관리 처럼 여러개의 업무를 동시에 하나의 서비스로 섞어서 정의하지 않는다.

REST API에서 /users, /products와 같이 주요 URI도 하나의 서비스 정의의 범위로 좋은 예가 된다.  


마이크로 서비스 아키텍쳐의 구조


마이크로 서비스 아키텍쳐의 구조는 다음과 같은 모양을 따른다.

각 컴포넌트는 서비스라는 형태로 구현되고 API를 이용하여 타 서비스와 통신을 한다.



배포 구조관점에서도 각 서비스는 독립된 서버로 타 컴포넌트와의 의존성이 없이 독립적으로 배포 된다.

예를 들어 사용자 관리 서비스는 독립적인 war파일로 개발되어, 독립된 톰캣 인스턴스에 배치된다. 확장을 위해서 서비스가 배치된 톰캣 인스턴스는 횡적으로 스케일 (인스턴스 수를 더함으로써)이 가능하고, 앞단에 로드 밸런서를 배치하여 서비스간의 로드를 분산 시킨다.



가장 큰 특징이, 애플리케이션 로직을 분리해서 여러개의 애플리케이션으로 나눠서 서비스화하고, 각 서비스별로 톰캣을 분산 배치한 것이 핵심이다.


데이타 분리


데이타 저장관점에서는 중앙 집중화된 하나의 통 데이타 베이스를 사용하는 것이 아니라 서비스 별로 별도의 데이타 베이스를 사용한다.       보통 모노리틱 서비스의 경우에는 하나의 통 데이타 베이스 (보통 RDBMS를 사용) 하는 경우가 일반적이지만, 마이크로 서비스 아키텍쳐의 경우, 서비스가 API에서 부터 데이타 베이스까지 분리되는 수직 분할 원칙 (Vertical Slicing)에 따라서 독립된 데이타 베이스를 갖는다.



데이타 베이스의 종류 자체를 다른 데이타 베이스를 사용할 수 도 있지만, 같은 데이타 베이스를 사용하더라도 db를 나누는 방법을 사용한다.

이 경우, 다른 서비스 컴포넌트에 대한 의존성이 없이 서비스를 독립적으로 개발 및 배포/운영할 수 있다는 장점을 가지고 있으나, 다른 컴포넌트의 데이타를 API 통신을 통해서만 가지고 와야 하기 때문에 성능상 문제를 야기할 수 있고, 또한 이 기종 데이타 베이스간의 트렌젝션을 묶을 수 없는 문제점을 가지고 있다. (이러한 데이타 분산에 의한 트렌젝션 문제는 SOA 때부터 있어 왔다.) 데이타 분산으로 인한 트렌젝션 문제는 뒤에서 조금 더 자세하게 설명하도록 한다.


API Gateway


마이크로 서비스 아키텍쳐 설계에 있어서 많이 언급되는 컴포넌트 중의 하나가 api gateway 라는 컴포넌트 이다. api gateway는 마치 프록시 서버 처럼 api들 앞에서 모든 api에 대한 end point를 통합하고, 몇가지 추가적인 기능을 제공하는 미들웨어로, SOA의 ESB (Enterprise Service Bus)의 경량화 버전이다. Apigateway가 마이크로 서비스 아키텍쳐 상에서 수행하는 주요 기능을 살펴보면 다음과 같다.

EndPoint 통합 및 토폴로지 정리

마이크로 서비스 아키텍쳐의 문제점 중의 하나는 각 서비스가 다른 서버에 분리 배포 되기 때문에, API의 End point 즉, 서버의 URL이 각기 다르다는 것이다.

사용자 컴포넌트는 http://user.server.com, 상품 컴포넌트는 http://product.server.com 과 같은 분리된 URL을 사용하는데, 이는 API 사용자 경험 관점에서도 사용하기가 불편하다. 특히 마이크로 서비스 아키텍쳐는 컴포넌트를 되도록이면 업무 단위로 잘게 짜르는 fine grained (작은 덩어리)의 서비스를 지향하기 때문에, 컴포넌트의 URL 수는 더 많이 늘어 날 수 있다.

API를 사용하는 클라이언트에서 서버간의 통신이나, 서버간의 API 통신의 경우 p2p(Point to Point)형태로 토폴로지가 복잡해지고 거미줄 모양의 서비스 컴포넌트간의 호출 구조는 향후 관리의 문제를 일으킬 수 있다. 하나의 end point를 변경하였을때, 제대로 관리가 되지 않을 경우가 있다.




<그림. P2P 형태의 토폴리지>

이러한 토폴로지상의 문제점을 해결하기 위해서 중앙에 서비스 버스와 같은 역할을 하는 채널을 배치 시켜서, 전체 토폴로지를 p2p에서 hub & spoke 방식으로 변환 시켜서, 서비스간 호출을 단순화 시킬 수 있다.




<그림. 버스 기반의 Hub & Spoke 토폴리지>

Orchestration


다른 기능으로는 orchestration 이라는 개념이 있다. 기존 open api의 mash up과 같은 개념으로, 여러개의 서비스를 묶어서 하나의 새로운 서비스를 만드는 개념이다.

예를 들어, 포인트 적립과, 물품 구매라는 서비스가 있을때, 이 두개의 서비스를 묶어서 “물품 구입시 포인트 적립”이라는 새로운 서비스를 만들어 낼 수 있다. 이러한 orchestration 기능은, api gateway를 통해서 구현될 수 있다.

이는 마이크로 서비스 아키텍쳐가 서비스 자체가 fine grained 형태로 잘게 쪼게졌기 때문에 가능한 일인데, 사실 orchestration을 api gateway 계층에서 하는 것은 gateway 입장에서 부담이 되는 일이다. 실제로 과거의 SOA 시절에 많은 ESB(Enterprise Service Bus) 프로젝트가 실패한 원인 중의 하나가 과도한 orchestration 로직을 넣어서 전체적인 성능 문제를 유발한 경우가 많았다. 그래서 orchestration 서비스의 활용은 마이크로 서비스 아키텍쳐에 대한 높은 이해와 api gateway 자체에 대한 높은 수준의 기술적인 이해를 필요로 한다.

실제로 넷플릭스의 경우 마이크로 서비스 아키텍쳐를 사용하면서, 여러개의 서비스들을 gateway 계층을 통해서 orchestration 하는 모델을 사용하고 있다. 


공통 기능 처리 (Cross cutting function handling)


또한 API에 대한 인증 (Authentication)이나, Logging과 같은 공통 기능에 대해서 서비스 컴포넌트 별로 중복 개발해야 하는 비효율성을 유발할 수 있다. api gateway에서 이러한 공통 기능을 처리하기 되면, api 자체는 비지니스 로직에만 집중을 하여 개발에 있어서의 중복등을 방지 할 수 있다.

mediation

이외에도 XML이나 네이티브 메세지 포맷을 json등으로 상호 변환해주는 message transformation 기능이나, 프로토콜을 변환하는 기능, 서비스간의 메세지를 라우팅해주는 기능등 여러가지 고급 mediation 기능을 제공을 하지만, api gateway를 최대한 가볍게 가져간다는 설계 원칙 아래서 가급 적이면 고급적인 mediation 기능을 사용할 때는 높은 수준의 설계와 기술적인 노하우를 동반해야 한다.


※ ESB vs APIgateway

SOA 프로젝트의 실패중의 하나가 ESB로 꼽히는 경우가 많은데, 이는 ESB를 Proxy나 Gateway처럼 가벼운 연산만이 아니라, 여러개의 서비스를 묶는 로직에  무겁게 사용했기 때문이다. (사용하면 안된다는 것이 아니라 잘 사용해야 한다는 것이다.) ESB는 메세지를 내부적으로 XML로 변환하여 처리하는데, XML 처리는 생각하는것 보다 파싱에 대한 오버헤드가 매우 크다.  또한 ESB의 고유적인 버스나 게이트웨이로써의 특성이 아니라 타 시스템을 통합 하기 위한 EAI적인 역할을 ESB를 이용해서 구현함으로써 많은 실패 사례를 만들어 내었다. 그래서 종종 ESB는 Enterprise Service Bus가 아니라 EnterpriSe nightmare Bus로 불리기도 한다. J

이러한 개념적인 문제를 해결하기 위해서 나온 제품군이 apigateway라는 미들웨어 제품군들인데, ESB와 기본적인 특성은 유사하나 기능을 낮추고 EAI의 통합 기능을 제거하고 API 처리에만 집중한 제품군들로, 클라우드상에서 작동하는 PaaS (Platform As A Service)형태의 서비스로는 apigee.com이나 3scale.com 등이 있고, 설치형 제품으로는 상용 제품인 CA社의 Layer7이나 오픈소스인 Apache Service Mix, MuleSoft의 ESB 제품 그리고 WSO2의 API Platform 등이 있다.

Apigateway 부분에 마이크로 서비스 아키텍쳐의 다른 부분 보다 많은 부분을 할애한 이유는, 컴포넌트를 서비스화 하는 부분에 까지는 대부분 큰 문제가 없이 적응을 하지만 apigateway의 도입 부분의 경우, 내부적인 많은 잡음이 날 수 있고, 또한 도입을 했더라도 잘못된 설계나 구현으로 인해서 실패 가능성이 비교적 높은 모듈이기 때문이다. 마이크로 서비스 아키텍쳐의 핵심 컴포넌트이기도 하지만, 도입을 위해서는 팀의 상당 수준의 높은 기술적인 이해와 개발 능력을 필요로 한다.


배포


마이크로 서비스 아키텍쳐의 가장 큰 장점 중의 하나가 유연한 배포 모델이다. 각 서비스가 다른 서비스와 물리적으로 완벽하게 분리되기 때문에 변경이 있는 서비스 부분만 부분 배포가 가능하다 예를 들어서, 사용자 관리 서비스 로직이 변경되었을 때, 모노리틱 아키텍쳐의 경우에는 전체 시스템을 재 배포해야 하지만, 마이크로 서비스 아키텍쳐의 경우에는 변경이 있는 사용자 관리 서비스 부분만 재 배포 하면 되기 때문에, 빠르고 전체 시스템의 영향도를 최소화한 수준에서 배포를 진행할 수 있다.


확장성


서비스 별로 독립된 배포 구조는 확장성에 있어서도 많은 장점을 가지고 오는데, 부하가 많은 특정 서비스에 대해서만 확장이 가능하여 조금 더 유연한 확장 모델을 가질 수 있다. 모노리틱 아키텍쳐의 경우에는 특정 서비스의 부하가 많아서 성능 확장이 필요할때, 전체 서버의 수를 늘리거나 각 서버의 CPU 수를 늘려줘야 하지만, 마이크로 서비스 아키텍쳐의 경우에는 부하를 많이 받는 서비스 컴포넌트 만 확장을 해주면 된다.


Conway’s Law (컨웨이의 법칙)


마이크로 서비스 아키텍쳐의 흥미로운 점중의 하나는 아키텍쳐 스타일의 조직 구조나 팀 운영 방식에 영향을 준다는 것인데, 마이크로 서비스 아키텍쳐는 컨웨이의 법칙에 근간을 두고 있다.

컨웨이의 법칙은 “소프트웨어의 구조는 그 소프트웨어를 만드는 조직의 구조와 일치한다”는 이론이다.

현대의 소프트웨어 개발은 주로 애자일 방법론을 기반으로 하는 경우가 많다. 애자일 팀의 구조는 2 피자팀(한팀의 인원수는 피자 두판을 먹을 수 있는 정도의 인원 수가 적절하다.)의 모델을 많이 따르는데, 한 팀이 7~10명정도로 이루어지고, 이 인원 수가 넘어가면 팀을 분리하는 모델이다.

마이크로 서비스 아키텍쳐는 각 컴포넌트를 팀에 배치해서 책임지고 개발하는 것을 근간으로 하며, 팀간의 의존성을 제거해서 각 팀이 컴포넌트 개발을 독립적으로할 수 있는 구조로 잡혀있다.


마이크로 서비스 아키텍쳐의 문제점


분홍빛 미래 처럼 보이는 마이크로 서비스 아키텍쳐는 아무런 문제가 없는 것일까? 당연히 여러가지 장점을 제공하는 대신에 그만한 단점을 가지고 있다.


성능


모노리틱 아키텍쳐는 하나의 프로세스 내에서 서비스간의 호출을 call-by-reference 모델을 이용한다. 반면 마이크로 서비스 아키텍쳐는 서비스간의 호출을 API 통신을 이용하기 때문에 값을 json이나 xml에서 프로그래밍에서 사용하는 데이타 모델 (java object등)으로 변환하는 marsharing 오버헤드가 발생하고 호출을 위해서 이 메세지들이 네트워크를 통해서 전송되기 때문에 그만한 시간이 더 추가로 소요된다.


메모리


마이크로 서비스 아키텍쳐는 각 서비스를 독립된 서버에 분할 배치하기 때문에, 중복되는 모듈에 대해서 그만큼 메모리 사용량이 늘어난다.

예를 들어 하나의 톰캣 인스턴스에서 사용자 관리와 상품 관리를 배포하여 운용할 경우, 하나의 톰캣을 운영하는데 드는 메모리와, 스프링 프레임웍과 같은 라이브러리를 사용하는데 소요되는 메모리 그리고 각각의 서비스 애플리케이션이 기동하는 메모리가 필요하다.

그러나 마이크로 서비스 아키텍쳐로 서비스를 배포할 경우 사용자 관리 서비스 배포와 상품 관리 서비스 배포를 위한 각각의 별도의 톰캣 인스턴스를 운용해야 하고, 스프링 프레임웍과 같은 공통 라이브러리도 각각 필요하기 때문에, 배포하고자 하는 서비스의 수 만큼 중복된 양의 메모리가 필요하게 된다.

위의 두 문제는 반드시 발생하는 문제점이기는 하나 현대의 인프라 환경에서는 크게 문제는 되지 않는다. (기존에 비해 상대적으로). 현대의 컴퓨팅 파워 자체가 워낙 발달하였고, 네트워크 인프라 역시 기존에 1G등에 비해서 내부 네트워크는 10G를 사용하는 등, 많은 성능상 발전이 있었다. 또한 메모리 역시 비용이 많이 낮춰지고 32bit에서 64bit로 OS들이 바뀌면서, 가용 메모리 용량이 크게 늘어나서 큰 문제는 되지 않는다. 또한 성능상의 문제는 비동기 패턴이나 캐슁등을 이용해서 해결할 수 있는 다른 방안이 많기 때문에 이 자체는 큰 문제가 되지 않는다.

그보다 더 문제점은 아래에서 언급하는 내용들인데,


테스팅이 더 어려움


마이크로 서비스 아키텍쳐의 경우 서비스들이 각각 분리가 되어 있고, 다른 서비스에 대한 종속성을 가지고 있기 때문에, 특정 사용자 시나리오나 기능을 테스트하고자 할 경우 여러 서비스에 걸쳐서 테스트를 진행해야 하기 때문에 테스트 환경 구축이나 문제 발생시 분리된 여러개의 시스템을 동시에 봐야 하기 때문에 테스팅의 복잡도가 올라간다.

운영 관점의 문제


운영 관점에서는 서비스 별로 서로 다른 기술을 사용할 수 있으며, 시스템이 아주 잘게 서비스 단위로 쪼게 지기 때문에 운영을 해야할 대상 시스템의 개수가 늘어나고, 필요한 기술의 수도 늘어나게 된다.


서비스간 트렌젝션 처리


구현상의 가장 어려운 점중의 하나가, 트렌젝션 처리이다. 모노리틱 아키텍쳐에서는 RDBMS를 사용하면서 하나의 애플리케이션 내에서 트렌젝션이 문제가 있으면 쉽게 데이타베이스의 기능을 이용해서 rollback을 할 수 있었다. 여러개의 데이타베이스를 사용하더라도, 분산 트렌젝션을 지원하는 트렌젝션 코디네이터 (JTS – Java Transaction Service)등을 이용해서 쉽게 구현이 가능했는데, API 기반의 여러 서비스를 하나의 트렌젝션으로 묶는 것은 불가능 하다.

쉽게 예를 들어서 설명을 하면, 계좌에서 돈을 빼는 서비스와, 계좌에 돈을 넣는 서비스가 있다고 하자. 이 둘은 API를 expose했을 때, 계좌에서 돈을 뺀 후, 계좌에 돈을 넣기 전에 시스템이 장애가 나면, 뺀 돈은 없어지게 된다. 모노리틱 아키텍쳐를 사용했을 경우에는 이러한 문제를 트렌젝션 레벨에서 롤백으로 쉽게 해결할 수 있지만 API 기반의 마이크로 서비스 아키텍쳐에서는 거의불가능하다.

사실 이 문제는 마이크로 서비스 아키텍쳐 이전에도, 서비스와 API를 기본 컨셉으로 하는 SOA에도 있었던 문제이다.

이러한 문제를 해결하기 위해서 몇가지 방안이 있는데,

그 첫번째 방법으로는 아예 애플리케이션 디자인 단계에서 여러개의 API를 하나의 트렌젝션으로 묶는 분산 트렌젝션 시나리오 자체를 없애는 방안이다. 분산 트렌젝션이 아주 꼭 필요할 경우에는 차라리 모노리틱 아키텍쳐로 접근하는 것이 맞는 방법이다. 앞서도 언급했듯이 마이크로 서비스 아키텍쳐의 경우, 금융이나 제조와 같이 트렌젝션 보장이 중요한 엔터프라이즈 시스템보다는 대규모 처리가 필요한 B2C 형 서비스에 적합하기 때문에, 아키텍쳐 스타일 자체가 트렌젝션을 중요시 하는 시나리오에서는 적절하지 않다.

그럼에도 불구하고, 트렌젝션 처리가 필요할 경우, 트렌젝션 실패시 이를 애플리케이션 적으로 처리해 줘야 하는 데, 이를 보상 트렌젝션(compensation transaction)이라고 한다. 앞의 계좌 이체 시나리오에서 돈을 뺀 후, 다른 계좌에 넣다가 에러가 났을 경우에, 명시적으로, 돈을 원래 계좌로 돌려주는 에러 처리 로직을 구현해야 한다.

마지막 방법으로 복합 서비스 (composite service)라는 것을 만들어서 활용하는 방법이 있는데, 복합 서비스란 트렌젝션을 묶어야 하는 두개의 시스템을 트렌젝션을 지원하는 네이티브 프로토콜을 이용해서 구현한 다음 이를 API로 노출 시키는 방법이다.

두개의 데이타 베이스는 XA(eXtended Architecture)와 같은 분산 트렌젝션 프로토콜을 써서 서비스를 개발하거나 또는 SAP나 Oracle 아답터와 같이 트렌젝션을 지원하는 네이티브 아답터를 사용하는 방법이다. 기존에 SOA에서 많이 했던 접근방법이기는 하나, 복합 서비스를 사용할 경우, 복합서비스가 서로 다른 두개의 서비스에 걸쳐서 tightly coupled하게 존재하기 때문에, 마이크로 서비스 아키텍쳐의 isolation(상호 독립적)인 사상에 위배되고 서비스 변경시에 이 부분을  항상 고려해야 하기 때문에 아키텍쳐상의 유연성이 훼손되기 때문에 꼭 필요하지 않은 경우라면 사용하지 않는 것이 좋다.


거버넌스 모델


거버넌스 (governance)란, 시스템을 개발하는 조직의 구조나 프로세스를 정의한 것으로, 일반적으로 중앙 집중화된 조직에서 표준 프로세스와 가이드를 기반으로 전체 팀을 운용하는 모델을 사용한다. 이를 중앙 집중형 거버넌스 모델 (Centralized governance model) 이라고 하는데, 이 경우 전체 시스템이 동일한 프로세스와 기술을 가지고 개발이 되기 때문에, 유지 보수가 용이하고 팀간의 인원 교체등이 편리하다는 장점을 가지고 있다. 전통적인 개발 모델들은 이러한 중앙 집중현 거버넌스 모델을 사용한다.

그러나 현대의 웹 개발의 경우, 오픈 소스 발달로 선택 가능한 기술들이 많고 각 요구 사항에 따라서 효율성 측면등을 고려할때 각각 최적화된 기술을 사용하는 것이 좋은 경우가 있다.

예를 들어, 전체 표준을 자바+RDBMS로 정했다 하더라도, 파일 업로드 다운로드 관련 컴포넌트는 io 성능과 많은 동시접속자를 처리할 수 있는 node.js가 유리하다던지, 데이타의 포맷은 복잡하지만, 복잡한 쿼리가 없을 경우에는 json document 기반의 mongodb와 같은 NoSQL등이 유리한 사례 등이 된다. 이러한 기술을 도입하기 위해서는 중앙 집중형 거버넌스 모델에서는 모든 개발팀을 교육 시키고, 운영 또한 준비를 해야하기 때문에 기술에 대한 적용 민첩성이 떨어지게 된다.

이러한 문제점을 해결 하는 거버넌스 모델이 분산형 거버넌스 모델 (De-Centralized governance model)인데, 이는 각 팀에 독립적인 프로세스와 기술 선택 권한을 주는 모델로, 각 서비스가 표준 API로 기능을 바깥으로 노출할 뿐 내부적인 구현 기술 구조는 추상화되어 가능한 사상이다

분산형 거버넌스 모델을 수행하려면, 이에 맞는 팀구조가 필요한데, 이 팀 구조는 다음과 같은 몇가지 특징을 가지고 있어야 한다.


Cross functional team


기존의 팀 모델은 역할별로 나뉘어진 모델로 팀을 구분한다. 기획팀,UX팀,개발팀,인프라 운영팀 등 공통적인 특성으로 나누는 것이 기존의 팀 모델이다. 이런 팀 모델은 리소스의 운영에 유연성을 부여한다. 개발 인력이 모자르면 팀 내에서 개발인원을 다른 프로젝트에서 충당하는 등의 리소스 운영이 가능하지만 반대로 팀간의 커뮤니케이션이 팀이라는 경계에 막혀서 원할하지 않고 협의에 걸리는 시간으로 인해서 팀의 운영 속도가 떨어진다.

cross function team 모델은 하나의 팀에 UX, 개발팀,인프라팀등 소프트웨어 시스템을 개발하는데 필요한 모든 역할을 하나의 팀에 구성하고 움직이는 모델로, 각 서비스 개발팀이 cross functional team이 되서 움직인다.



<그림 역할 중심의 개발팀 과 cross functional team에 대한 모델 비교>

이 경우 서비스 기획에서 부터 설계,개발,운영이 가능해지고 다른 팀에 대한 의존성이 없어짐으로써 빠른 서비스 개발이 가능해진다.


You build,You run-Devops


기술에 대한 독립성을 가지려면 구현 뿐만 아니라 운영 또한 직접할 수 있는 능력을 가져야 한다. 그래서 개발과 운영을 하나의 조직에 합쳐 놓는 구조를 Devops라고 한다.

Devops는 Development와 Operation을 합성한 단어로, 개발팀과 운영팀이 다른 팀으로 분리되어 있어서 발생하는 의사 소통의 문제점을 해결하고, 개발이 운영을 고려하고, 운영에서 발생하는 여러 문제점과 고객으로부터의 피드백을 빠르게 수용하여 서비스 개선에 반영하는 개발 모델이다.

이런 모델이 가능해진 이유는 운영팀만의 고유 영역이었던 인프라에 대한 핸들링이 클라우드의 도입으로 인해서 쉬워져서, 애플리케이션 개발자도 웹사이트를 통해서 손쉽게 디스크나 네트워크 설정, 서버 설정등이 가능해졌기 때문이다.

Devops는 대단히 좋은 모델이고 아마존이나 넷플릭스등이 적용하고 있는 모델이기는 하나, 이 역시 대단히 높은 수준의 팀의 성숙도가 필요하다.

개발자가 애플리케이션 개발 뿐만 아니라, 인프라에 대한 설계 및 운영까지 담당해야 하기 때문에 기존의 애플리케이션만 개발하던 입장에서는 대단히 부담이 되는 일이다.

좋은 모델이기는 하지만 충분히 준비가 되지 않은 상태에서 넘어가게 되면은 운영상의 많은 장애를 유발하기 때문에, 팀의 성숙도에 따라서 심각하게 고민해보고 적용을 해보기를 권장한다.


Project vs product


분산형 거버넌스 모델에서 중요한 점 중의 하나는 연속성이다. 거버넌스를 분산 시켜버렸기 때문에 팀별로 다른 형태의 표준과 기술 프로세스를 통해서 개발을 하기 때문에, 새로운 인원이 들어오거나 다른 팀으로 인원이 이동하였을 경우 팀에 맞는 형태의 재 교육이 필요하고 그간의 축적된 노하우가 100% 활용되지 못할 수 가 있기 때문에 가능하면 팀원들은 계속해서 해당 서비스 개발에 집중할 필요가 있다.

이를 위해서는 프로젝트의 컨셉 변화가 필요한데, 일반적으로 프로젝트란 일정 기간에 정해진 요구 사항을 구현하는데 목표가 잡혀 있으며, 프로젝트가 끝나면 인원은 다시 흩어져서 새로운 프로젝트에 투입 되는 형태로 역할 중심의 프로젝트팀 운용 방식에는 적절하다.

그러나 분산형 거버넌스 모델에서는 팀원의 영속성을 보장해줘야 하는데 이를 위해서는 프로젝트가 아니라 프로덕트(즉 상품)형태의 개념으로 개발 모델이 바뀌어야 한다. 팀은 상품에 대한 책임을 지고, 요구사항 정의 발굴에서 부터 개발 그리고 운영까지 책임을 지며, 계속해서 상품을 개선해 나가는 활동을 지속해야 한다. 이를 상품 중심의 개발팀 모델이라고 한다.


Self-organized team


이러한 요건등이 만족 되면, 팀은 독립적으로 서비스 개발을 할 수 있는 형태가 된다. 스스로 기획하고 개발하며 운영을 하며 스스로 서비스를 발전 시키는 하나의 회사와 같은 개념이 되는 것이다.

이렇게 독립적인 수행 능력을 가지고 있는 팀 모델을 self-organized team 모델이라고 한다.


Alignment 


이러한 분산형 거버넌스 모델을 수행하기 전에 반드시 주의해야 할 점이 있는데, alignment 라는 개념이다 alignment는 각 팀간의 커뮤니케이션 방법이나 프로세스등 최소한 표준과 기술적인 수준을 맞추는 과정인데, 쉽게 이야기해서 개발 경험이 전혀 없는 대학을 갓졸업한 사람들로 팀을 만들고, 기존의 팀들은 4~5년차 경력 인원들만으로 팀을 만들어서 전체 팀을 운용하면 어떻게 될까?

마이크로 서비스 아키텍쳐는 각 서비스들이 상호 의존성을 가지고 있기 때문에, 개발경험이 없는 팀이 전체 팀의 개발 속도를 못 따라오고, 또한 품질등에도 심각한 문제가 생긴다. 그래서 어느 일정 수준 이상으로 팀의 능력을 끌어 올려주고, 전체 팀에서 사용하는 최소한의 공통 프로세스등에 대해서는 서로 맞추어 놓을 필요가 있다. 이것이 바로 alignment 의 개념이다.

분산형 거버넌스 모델을 잘못 해석하거나 악용이 되면 팀에게 무조건적인 자치권을 부여하는 것으로 오역되서.. “분산형 거버넌스가 대세랍니다. 우리팀은 우리가 알아서 할테니 신경 끄세요.” 라는 형태의 잘못된 요청으로 전체 팀과 전체 시스템 아키텍쳐를 망쳐 버릴 수 있다.

제대로 된 해석은 “우리는 전체 팀이 나가야 할 방향과 비지니스 밸류에 대해서 이해를 하고 있습니다. 또한 이미 팀간의 커뮤니케이션이나 전체 시스템 구조에 대한 이해를 하고 있습니다. 이를 바탕으로 조금 더 빠른 개발과 효율성을 위한 모든 기능(역할)을 가지고 있는 팀을 운영하고자 합니다.” 가 제대로 된 해석이라고 볼 수 있겠다.


Evolutionary Model (진화형 모델)


지금 까지 간략하게나마 마이크로 서비스 아키텍쳐에 대해서 알아보았다.

마이크로 서비스 아키텍쳐는 서비스의 재사용성, 유연한 아키텍쳐 구조, 대용량 웹 서비스를 지원할 수 있는 구조등으로 많은 장점을 가지고 있지만, 운영하는 팀에 대해서 높은 성숙도를 필요로 한다. 그래서 충분한 능력을 가지지 못한 팀이 마이크로 서비스 아키텍쳐로 시스템을 개발할 경우에는 많은 시행 착오를 겪을 수 있다.

마이크로 서비스 아키텍쳐를 적용할때는 처음 부터 시스템을 마이크로 서비스 아키텍쳐 형태로 설계해서 구현할 수 도 있겠지만, 모노리틱 시스템에서 부터 시작하여, 비지니스 운용시 오는 문제점을 기반으로 점차적으로 마이크로 서비스 아키텍쳐 형태로 진화 시켜 나가는 방안도 좋은 모델이 된다. 비지니스와 고객으로 부터 오는 피드백을 점차적으로 반영 시켜나가면서 동시에 팀의 성숙도를 올려가면서 아키텍쳐 스타일을 변화 시켜가는 모델로, 많은 기업들이 이런 접근 방법을 사용했다. 트위터의 경우에도, 모노리틱 아키텍쳐에서 시작해서 팀의 구조를 점차적으로 변환 시켜 가면서 시스템의 구조 역시 마이크로 서비스 아키텍쳐 형태로 전환을 하였고, 커머스 시장에서 유명한 이베이 같은 경우에도, 그 시대의 기술적 특성을 반영하면서 비지니스의 요구 사항을 적절히 반영 시켜가면서 시스템을 변화 시켜 나가는 진화형 모델로 아키텍쳐를 전환 하였다.


SOA와 비교


마이크로 서비스 아키텍쳐는 종종 SOA와 비교 되며, SOA는 틀리고 마이크로 서비스 아키텍쳐는맞다 흑백 논리 싸움이 벌어지고는 하는데,

SOA와 마이크로 서비스 아키텍쳐는 사실상 다른 개념이 아니라 SOA가 마이크로 서비스 아키텍쳐에 대한 조상 또는 큰 수퍼셋의 개념이다. 흔히 SOA가 잘못되었다고 이야기 하는 이유는 SOA를 아키텍쳐 사상으로 보는 것이 아니라 SOAP 기반의 웹서비스나, Enterprise Service Bus와 같은 특정 제품을 SOA로 인식하기 때문이다. SOA는 말 그대로 설계에 대한 사상이지 특정 기술을 바탕으로 한 구현 아키텍쳐가 아니다.

큰 의미에서 보자면 마이크로 서비스 아키텍쳐의 서비스 역시, SOA에서 정의한 서비스 중에서 fine grained 서비스로 정의되는 하나의 종류이며, api gateway역시 SOA 에서 정의한 ESB의 하나의 구현방식에 불과 하다.

만약에 기회가 된다면 마이크로 서비스 아키텍쳐에 대해 제대로 이해하기 위해서 SOA 를 반드시 공부해보기를 바란다.


결론


마이크로 서비스 아키텍쳐는 대용량 웹시스템에 맞춰 개발된 API 기반의 아키텍쳐 스타일이다. 대규모 웹서비스를 하는 많은 기업들이 이와 유사한 아키텍쳐 설계를 가지고 있지만, 마이크로 서비스 아키텍쳐가 무조건 정답은 아니다. 하나의 설계에 대한 레퍼런스 모델이고, 각 업무나 비지니스에 대한 특성 그리고 팀에 대한 성숙도와 가지고 있는 시간과 돈과 같은 자원에 따라서 적절한 아키텍쳐 스타일이 선택되어야 하며, 또한 아키텍쳐는 처음 부터 완벽한 그림을 그리기 보다는 상황에 맞게 점진적으로 진화 시켜 나가는 모델이 바람직하다.

 특히 근래의 아키텍쳐 모델은 시스템에 대한 설계 사상 뿐만 아니라 개발 조직의 구조나 프로젝트 관리 방법론에 까지 영향을 미치기 때문에 단순히 기술적인 관점에서가 아니라 조금 더 거시적인 관점에서 고려를 해볼 필요가 있다.

 

참고 자료

Ebay 아키텍쳐 : http://www.addsimplicity.com/downloads/eBaySDForum2006-11-29.pdf

Netflix 아키텍쳐 : http://techblog.netflix.com/2013/01/optimizing-netflix-api.html

infoQ Microservice Architecture : http://www.infoq.com/articles/microservices-intro

MicroService 개념 http://microservices.io/patterns/microservices.html

Martin folwer : http://martinfowler.com/articles/microservices.html

Dzone microservice architecture : http://java.dzone.com/articles/microservice-architecture

Thought works의 PPT : http://www.infoq.com/presentations/Micro-Services

node.js로 apigateway 만들기 : 정리 잘되어 있음. http://plainoldobjects.com/presentations/nodejs-the-good-parts-a-skeptics-view/

저작자 표시
신고

Microservice architecture note

아키텍쳐 /SOA | 2014.08.20 16:37 | Posted by 조대협

MSA (Microservice Architecture) 

자료 수집


참고 자료

Ebay 아키텍쳐 : http://www.addsimplicity.com/downloads/eBaySDForum2006-11-29.pdf

Netflix 아키텍쳐 : http://techblog.netflix.com/2013/01/optimizing-netflix-api.html

infoQ Microservice Architecture : http://www.infoq.com/articles/microservices-intro

MicroService 개념 http://microservices.io/patterns/microservices.html

Martin folwer : http://martinfowler.com/articles/microservices.html

Dzone microservice architecture : http://java.dzone.com/articles/microservice-architecture

Thought works의 PPT : http://www.infoq.com/presentations/Micro-Services

node.js로 apigateway 만들기 : 정리 잘되어 있음. http://plainoldobjects.com/presentations/nodejs-the-good-parts-a-skeptics-view/


Conway's 법칙에 연관됨

You build, You run - Devops, Amazon

De-Centralized governance - 기술 표준화 보다는 다양한 기술을 허가. Microserice들을 스크립트 언어로 빠르게 만들어 버림. 

Cross platform, Self organized team 모델 지향 - Align 되기전에 Self organized로 이동되면. 망함. 

운영이 HELL이다. 높은 운영 능력, 장애 처리, Devops 필요.



==> 공감 x 100배 (나만 겪는 문제가 아니구만..)

ESB (Enterprise Night Bus.. ) 


저작자 표시
신고

'아키텍쳐  > SOA' 카테고리의 다른 글

Microservice architecture note  (0) 2014.08.20
Open API design  (0) 2013.07.06
통신 사업자의 SDP의 필수 컴포넌트  (0) 2010.08.03
SDP (Service Delivery Platform)  (1) 2009.09.15
모차세대 시스템의 WAS 아키텍쳐 Blue Print  (8) 2009.07.30
EAI관점에서 본 SOA  (6) 2009.07.29

OAuth 2.0 노트

아키텍쳐 /Security & IDM | 2014.08.11 17:05 | Posted by 조대협

OAuth 용어 정리

Resource Owner (사용자)

Authorization Server (인증서버

Resource Server (REST API)



 

OAuth 2.0 grant flow

Authorization code grant flow

주로 Web Application에서 사용됨

Implicit grant flow

자바스크립트 애플리케이션에서 많이 사용됨. 스크립트 단에서는 credential 등이 노출 될 수 있으니, 주로 Read only 용도로 많이 사용함. accessToken이 노출될것을 전제로 함.

모바일 애플리케이션도 많이 사용하는걸로 나오네??

Ÿ   Used in public clients

Ÿ   It's is a redirection-based flow (similar to the one in the authorization code grant)

Ÿ   The access token is received as a parameter of the redirection endpoint upon successful completion of the request, similar to the authorization code parameter in the authorization request response in the authorization code grant



Flow

     The first step is initiation of the flow. The client redirects the User agent to the Authorization server by using the authorization endpoint, the client identifier, and the redirection endpoint that will be used for the response.

     The Authorization server authenticates the Resource owner and requests his decision whether to authorize or deny the request.

     If the Resource owner authorizes the request (which is assumed), he is redirected back with response information, using the supplied redirection endpoint that was provided with the initial request. The response information is contained in the URL fragment that contains the access token and other parameters (we'll see the difference between a regular URL parameter and one found in a URL fragment in the detailed overview).

     Now that the User agent (the browser) is redirected back, the access token included in the response is passed to the Client application.

Client Server Application Case

Mobile App Case

(웹이 아니기 때문에, Redirect 처리를 어떻게 해야 할지 고민해야 함.

Samsung Account와 같이 전용 APK를 넣는 방식이나, 웹 페이지 Scrapping 방식등이 있음)

 

Resource owner password credential grant flow

직접 ID,PASSWORD를 보내는 방식으로, 1st level 파트너나 자사 시스템에 많이 사용.

기존의 HTTP BASIC이나 HTTP Digest 인증 방식을 migration하기가 용이함



     The resource owner (for example, the user) supplies the Client application with his username and password.

     The client application makes a request to the Authorization server, including the user's credentials and also his own identifier and secret.

     The Authorization server authenticates the client based on his identifier and secret, checks whether it is authorized for making this request, and checks the resource owner credentials and other parameters supplied. If all checks pass successfully, the Authorization server returns an access token in response.

Client credential grant flow

Userless 상태에서 많이 사용됨. (API 키와 유사한 방식)

 

 

저작자 표시
신고

'아키텍쳐  > Security & IDM' 카테고리의 다른 글

서버와 APNS(애플푸쉬서버)와의 보안 메커니즘  (3) 2014.10.07
OAuth 2.0 노트  (0) 2014.08.11
OAuth 2.0 based API 인증 메모  (0) 2014.06.05
Digital Signing의 개념  (0) 2014.05.21
Java keystore file  (0) 2013.09.27
SSL/TLS 관련 개념 링크  (1) 2013.09.24

REST API 디자인 가이드

아키텍쳐 /WEB 2.0 | 2014.06.12 21:54 | Posted by 조대협

REST API 디자인 가이드

조대협(http://bcho.tistory.com)

REST API 디자인을 보면, REST 사상에 맞춰서 제대로 디자인 (CRUD를 HTTP method에 맞춘)하기도 어렵고, URI Convention등이나 보안, 버전 관리등 고려할 사항이 많다. 이번 글에서는 REST API를 디자인에 대한 가이드를 소개하고자 한다.

동사보다는 명사를 사용하자

URL을 심플하고 직관적으로 만들자

REST API를 URL만 보고도, 직관적으로 이해할 수 있어야 한다
URL을 길게 만드는것 보다, 최대 2 depth 정도로 간단하게 만드는 것이 이해하기 편하다.

/dogs
/dogs/1234

URL에 동사보다는 명사를 사용한다.

REST API는 리소스에 대해서 행동을 정의하는 형태를 사용한다. 예를 들어서

POST /dogs

는 /dogs라는 리소스를 생성하라는 의미로, URL은 HTTP Method에 의해 CRUD (생성,읽기,수정,삭제)의 대상이 되는 개체(명사)라야 한다.
잘못된 예들을 보면

HTTP Post : /getDogs
HTTP Post : /setDogsOwner

위의 예제는 행위를 HTTP Post로 정의하지 않고, get/set 등의 행위를 URL에 붙인 경우인데, 좋지 않은 예 이다. 이보다는

HTTP Get : /dogs
HTTP Post : /dogs/{puppy}/owner/{terry}

를 사용하는 것이 좋다.
일반적으로 권고되는 디자인은 다음과 같다.

리소스POSTGETPUTDELETE
createreadupdatedelete
/dogs새로운 dogs 등록dogs 목록을 리턴Bulk로 여러 dogs 정보를 업데이트모든 dogs 정보를 삭제
/dogs/baduk에러baduk 이라는 이름의 dogs 정보를 리턴baduk이라는 이름의 dogs 정보를 업데이트baduk 이라는 이름의 dogs 정보를 삭제

단수(Singular) 보다는 복수(Plural)형 명상를 사용한다.

되도록이면 추상적인 이름보다 구체적인 이름을 사용하자

리소스간의 관계를 표현하는 방법

Option A.

다른 리소스와의 관계를 표현. 예를 들어 owner가 가지고 있는 개(dogs) 목록

GET /owner/{terry}/dogs

와 같이 /resource명/identifier/other-related-resource 형태로, 해당 리소스에 대한 경로를 /resource명/{그 리소스에 대한 identifier}/{연관되는 다른 리소스 other-related-resource} 형태로 표현한다.

Option B.

https://usergrid.incubator.apache.org/docs/relationships/ 에 보면 다른 형태의 관계 정의 방법에 대해서 나와 있는데, 조금 더 구체적인 API 관계 정의 방법은 다음과 같다.

/resource/identifier/relation/other-related-resource
GET /owner/terry/likes/dogs

이 방식은 리소스간의 관계(relationship)을 URL 내에 정의하는 방법으로,훨씬 더 명시적일 수 있다. (세련되어 보이지는 않지만)
리소스간의 관계가 복잡하지 않은 서비스의 경우에는 Option A를, 리소스간의 관계가 다소 복잡한 경우에는 Option B를 사용하도록 한다.

에러 처리

에러 처리의 기본은 HTTP Response Code를 사용한후, Response body에 error detail을 사용해주는 것이 좋다.

Use HTTP Status Code

HTTP Status Code는 대략 70개의 코드가 있다. 일반적인 개발자들이 모든 코드를 기억할리는 없고, 에러 코드에서는 자주 사용되는 몇개의 코드만 의미에 맞춰서 사용하는 것이 좋다.
Google의 GData의 경우에는 10개, Neflix의 경우에는 9개, Digg의 경우에는 8개를 사용한다.
(※ http://info.apigee.com/Portals/62317/docs/web%20api.pdf)

  • Google GData
    200 201 304 400 401 403 404 409 410 500
  • Netflix
    200 201 304 400 401 403 404 412 500
  • Digg
    200 400 401 403 404 410 500 503

필자의 경우, 아래와 같은 정도의 HTTP Code를 사용하기를 권장한다.

  • 200 성공
  • 400 Bad Request - field validation 실패시
  • 401 Unauthorized - API 인증,인가 실패
  • 404 Not found
  • 500 Internal Server Error - 서버 에러

자세한 HTTP Status Code는 http://en.wikipedia.org/wiki/Http_error_codes 를 참고하기 바란다.

Error Message

HTTP Status Code 이외에, Response body에 detail한 에러 정보를 표현하는 것이 좋은데,
Twillo의 Error Message 형식의 경우

HTTP Status Code : 401
{“status”:”401”,”message”:”Authenticate”,”code”:200003,”more info”:”http://www.twillo.com/docs/errors/20003"}

와 같이 표현하는데, 에러 코드 #와 해당 에러 코드 #에 대한 Error dictionary link를 제공한다.
비단 API 뿐 아니라, 잘 정의된 소프트웨어 제품의 경우에는 별도의 Error # 에 대한 Dictionary 를 제공하는데, Oracle의 WebLogic의 경우에도http://docs.oracle.com/cd/E24329_01/doc.1211/e26117/chapter_bea_messages.htm#sthref7 와 같이 Error #와, 이에 대한 자세한 설명과, 조치 방법등을 설명한다. 이는 개발자나 Trouble Shooting하는 사람에게 많은 정보를 제공해서, 조금 더 디버깅을 손쉽게 한다. (가급적이면 Error Code #를 제공하는 것이 좋다.)

Error Stack

에러메세지에서 Error Stack 정보를 출력하는 것은 대단히 위험한 일이다. 내부적인 코드 구조와 프레임웍 구조를 외부에 노출함으로써, 해커들에게, 해킹을 할 수 있는 정보를 제공하기 때문이다. 일반적인 서비스 구조에서는 아래와 같은 에러 스택정보를 API 에러 메세지에 포함 시키지 않는 것이 바람직 하다.

log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: stacktrace.log (Permission denied)
at java.io.FileOutputStream.openAppend(Native Method)
at java.io.FileOutputStream.(FileOutputStream.java:177)
at java.io.FileOutputStream.(FileOutputStream.java:102)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:290)
at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:164)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

그렇지만, 내부 개발중이거나 디버깅 시에는 매우 유용한데, API 서비스를 개발시, 서버의 모드를 production과 dev 모드로 분리해서, 옵션에 따라 dev 모드등으로 기동시, REST API의 에러 응답 메세지에 에러 스택 정보를 포함해서 리턴하도록 하면, 디버깅에 매우 유용하게 사용할 수 있다.

버전 관리

API 정의에서 중요한 것중의 하나는 버전 관리이다. 이미 배포된 API 의 경우에는 계속해서 서비스를 제공하면서,새로운 기능이 들어간 새로운 API를 배포할때는 하위 호환성을 보장하면서 서비스를 제공해야 하기 때문에, 같은 API라도 버전에 따라서 다른 기능을 제공하도록 하는 것이 필요하다.
API의 버전을 정의하는 방법에는 여러가지가 있는데,

  • Facebook ?v=2.0
  • salesforce.com /services/data/v20.0/sobjects/Account
    필자의 경우에는

    {servicename}/{version}/{REST URL}
    example) api.server.com/account/v2.0/groups

형태로 정의 하는 것을 권장한다.
이는 서비스의 배포 모델과 관계가 있는데, 자바 애플리케이션의 경우, account.v1.0.war, account.v2.0.war와 같이 다른 war로 각각 배포하여 버전별로 배포 바이너리를 관리할 수 있고, 앞단에 서비스 명을 별도의 URL로 떼어 놓는 것은 향후 서비스가 확장되었을 경우에, account 서비스만 별도의 서버로 분리해서 배포하는 경우를 생각할 수 있다.
외부로 제공되는 URL은 api.server.com/account/v2.0/groups로 하나의 서버를 가르키지만, 내부적으로, HAProxy등의 reverse proxy를 이용해서 이런 URL을 맵핑할 수 있는데, api.server.com/account/v2.0/groups를 내부적으로 account.server.com/v2.0/groups 로 맵핑 하도록 하면, 외부에 노출되는 URL 변경이 없이 향후 확장되었을때 서버를 물리적으로 분리해내기가 편리하다.

페이징 처리와 Partial response

페이징

큰 사이즈의 리스트 형태의 응답을 처리하기 위해서 필요한 것은 페이징 처리와 partial response 처리이다. 리스트 내용이 1000,000개인데, 이를 하나의 HTTP Response로 처리하는 것은 서버 성능, 네트워크 비용도 문제지만 무엇보다 비현실적이다. 그래서, 페이징을 고려하는 것이 중요하다.
페이징을 처리하기 위해서는 여러가지 디자인이 있다.

예를 들어 100번째 레코드부터 125번째 레코드까지 받는 API를 정의하면

  • Facebook API 스타일 : /record?offset=100&limit=25
  • Twitter API 스타일 : /record?page=5&rpp=25 (RPP는 Record per page로 페이지당 레코드수로 RPP=25이면 페이지 5는 100~125 레코드가 된다.)
  • LikedIn API 스타일 : /record?start=50&count=25

apigee의 API가이드를 보면 좀더 직관적이라는 이유로 페이스북 스타일을 권장하고 있다.
record?offset=100&limit=25

Partial Response (Optional)

리소스에 대한 응답 메세지에 대해서 굳이 모든 필드를 포함할 필요가 없는 케이스가 있다. 예를 들어 페이스북 FEED의 경우에는 사용자 ID, 이름, 글 내용, 날짜, 좋아요 카운트, 댓글, 사용자 사진등등 여러가지 정보를 갖는데, API를 요청하는 Client의 용도에 따라 선별적으로 몇가지 필드만이 필요한 경우가 있다. 필드를 제한하는 것은 전체 응답의 양을 줄여서 네트워크 대역폭(특히 모바일에서) 절약할 수 있고, 응답 메세지를 간소화하여 파싱등을 간략화할 수 있다.
그래서 몇몇 잘 디자인된, REST API의 경우 이러한 Partial Response 기능을 제공하는데, 주요 서비스들을 비교해보면 다음과 같다.

  • Linked in : /people:(id,first-name,last-name,industry)
  • Facebook : /terry/friends?fields=id,name
  • Google : ?fields=title,media:group(media:thumnail)
    Linked in 스타일의 경우 가독성은 높지만 :()로 구별하기 때문에, HTTP 프레임웍으로 파싱하기가 어렵다. 전체를 하나의 URL로 인식하고, :( 부분을 별도의 Parameter로 구별하지 않기 때문이다.
    Facebook과 Google은 비슷한 접근 방법을 사용하는데, 특히 Google의 스타일은 더 재미있는데, group(media:thumnail) 와 같이 JSON의 Sub-Object 개념을 지원한다.
    Partial Response는 Google 스타일을 이용하는 것을 권장한다.

검색

검색은 일반적으로 HTTP GET에서 Query String에 검색 조건을 정의하는 경우가 일반적인데, 이 경우 검색조건이 다른 Query String과 섞여 버릴 수 있다. 예를 들어 name=cho이고, region=seoul인 사용자를 검색하는 검색을 Query String만 사용하게 되면 다음과 같이 표현할 수 있다.
/users?name=cho&region=seoul
그런데, 여기에 페이징 처리를 추가하게 되면

/users?name=cho&region=seoul&offset=20&limit=10

페이징 처리에 정의된 offset과 limit가 검색 조건인지 아니면 페이징 조건인지 분간이 안간다. 그래서, 쿼리 조건은 하나의 Query String으로 정의하는 것이 좋은데

/user?q=name%3Dcho,region%3Dseoul&offset=20&limit=10

이런식으로 검색 조건을 URLEncode를 써서 “q=name%3Dcho,region%3D=seoul” 처럼 (실제로는 q= name=cho,region=seoul )표현하고 Deleminator를 , 등을 사용하게 되면 검색 조건은 다른 Query 스트링과 분리된다.
물론 이 검색 조건은 서버에 의해서 토큰 단위로 파싱되어야 하낟.

전역 검색과 리소스 검색

다음으로는 검색의 범위에 대해서 고려할 필요가 있는데, 전역 검색은 전체 리소스에 대한 검색을, 리소스에 대한 검색은 특정 리소스에 대한 검색을 정의한다.
예를 들어 시스템에 user,dogs,cars와 같은 리소스가 정의되어 있을때,id=’terry’인 리소스에 대한 전역 검색은

/search?q=id%3Dterry

와 같은 식으로 정의할 수 있다. /search와 같은 전역 검색 URI를 사용하는 것이다.
반대로 특정 리소스안에서만의 검색은

/users?q=id%3Dterry

와 같이 리소스명에 쿼리 조건을 붙이는 식으로 표현이 가능하다.

HATEOAS (Optional)

HATEOS는 Hypermedia as the engine of application state의 약어로, 디자인의 요지는 하이퍼미디어의 특징을 이용하여 HTTP Response에 다음 Action에 대한 HTTP Link를 함께 리턴하는 것이다.
예를 들어 앞서 설명한 페이징 처리의 경우, 리턴시, 전후페이지에 대한 링크를 제공한다거나

HTTP GET users?offset=10&limit=5
{
[
{‘id’:’user1’,’name’:’terry’}
,{‘id’:’user2’,’name’:’carry’}
]
,’links’ :[
{
‘rel’:’pre_page’,
‘href’:’http://xxx/users?offset=6&limit=5
}
,
{
‘rel’:’next_page’,
‘href’:’http://xxx/users?offset=11&limit=5
}
]
}
와 같이 표현하거나
연관된 리소스에 대한 디테일한 링크를 표시 하는 것등에 이용할 수 있다.
HTTP GET users/terry
{
‘id’:’terry’
‘links’:[{
‘rel’:’friends’,
‘href’:’http://xxx/users/terry/friends
}]
}

HATEOAS를 API에 적용하게 되면, Self-Descriptive 특성이 증대되어 API에 대한 가독성이 증가하는 장점을 가지고 있기는 하지만, 응답 메세지가 다른 리소스 URI에 대한 의존성을 가지기 때문에, 구현이 다소 까다롭다는 단점이 있다.
요즘은 Spring과 같은 프레임웍에서 프레임웍 차원에서 HATEOAS를 지원하고 있으니 참고하기 바란다.http://spring.io/understanding/HATEOAS

단일 API URL

API 서버가 물리적으로 분리된 여러개의 서버에서 동작하고 있을때, user.apiserver.com, car.apiserver.com과 같이 API 서비스마다 URL이 분리되어 있으면 개발자가 사용하기 불편하다. 매번 다른 서버로 연결을 해야하거니와 중간에 방화벽이라도 있으면, 일일이 방화벽을 해제해야 한다.
API 서비스는 물리적으로 서버가 분리되어 있더라도 단일 URL을 사용하는 것이 좋은데, 방법은 HAProxy나 nginx와 같은 reverse proxy를 사용하는 방법이 있다.
HAProxy를 앞에 새우고 api.apiserver.com이라는 단일 URL을 구축한후에
HAProxy 설정에서

api.apiserver.com/user는 user.apiserver.com 로 라우팅하게 하고
api.apiserver.com/car 는 car.apiserver.com으로 라우팅 하도록 구현하면 된다.

보안

API 서비스에 있어서 보안은 매우 중요한 요소이다. API 에 대한 보안은 다음과 같이 보안 대상에 따라서 몇가지로 나눠진다.

인증

인증은, API를 호출하는 클라이언트가 VALID한 사용자인지, 불법적인 사용자인지를 구별하는 방식이다.

HTTP Basic Auth

가장 쉬운 방식으로는 사용자 id,password를 표준 HTTP Basic Auth에 넣어서 전송하는 방식으로 사용자 단위의 인증과 권한 컨트롤이 가능하다는 장점을 가지고 있다. 그러나 이 경우, 매번 사용자 id와 password가 네트워크를 통해서 전송되기 때문에, 해커에 의해서 사용자 id,password가 누출될 수 있다. 사용자 id,password가 누출되면 API 호출 권한뿐만 아니라 웹에 로그인해서 다른 서비스를 사용하는 등 치명적이기 때문에 그리 권장되지 않는 방법이다.
SSL을 사용해서 암호화할 수 는 있겠지만 기본적으로 SSL은 Man in the middle attack (중간에 인증서를 가로체서 SSL 패킷을 열어보는 방법) 에 취약하기 때문에 완벽하다고 볼 수 없다.

Access Token

매번 네트워크를 통해서 사용자 id,password를 보내는 것이 위험하다면, 처음 인증시에만 id,password를 보내고, 인증이 성공하면 서버에서 access_token을 발급하여 API 호출시 access_token으로만 호출하는 방식이다. (OAuth2.0이 유사한 메커니즘을 사용한다.) 이 경우 API를 호출하는 클라이언트가 access_token을 저장하는 메카니즘을 가져야 한다. 또한 access_token이 누출될때를 대비하여, 서버쪽에서 compromised된 (노출된/오염된) token의 경우 revoke(사용금지 처리)를 하고, 클라이언트에게 다시 access_token을 발급하도록 하는 메커니즘과, Expire time을 둬서 주기적으로 token을 교체하도록 하는 방식이 좋다.

API Key

API Key 시나리오는 일반적으로 API 제공자가 API 포탈등을 통해서, 개발자를 인증하고 개발자에게 API Key를 발급한후, 개발자가 API Key를 애플리케이션 코드내에 탑재해서 사용하는 방법을 사용한다. API를 외부 파트너에게 공개하는 경우에 손쉽게 사용할 수 있으며, 꽤 많이 사용되던 방식이다. 단 애플리케이션 (특히 모바일 애플리케이션)이 디컴파일 될 경우 API Key가 누출될 수 있는 위험성을 가지고 있기 때문에, API Key를 잘 관리 하는 것이 중요하다. (난독화를 한다던가)
이 시나리오의 경우 애플리케이션 단위의 인증을 하기 때문에 앞서 설명한 두 방식처럼 사용자 단위의 인증은 불가능 하다.
(사용자 단위의 인증이 필요한 경우 API Key로 애플리케이션을 인증한 후에, 클라이언트 마다 새로운 access_token을 발급하는 방식을 사용할 수 있다. 사실 이게 OAuth 2.0의 client_secret과 access_token 시나리오와 유사하다.)

OAuth 2.0 (Recommended)

OAuth는 근래에 가장 많이 사용되는 API 인가/인증 기술이다. 특징중의 하나는 Authentication(인증)만이 아니라 권한에 대한 통제(Authorization)이 가능하다는 특징을 가지고 있으며, 3 legged 인증을 통해서, 파트너사가 API를 사용할 경우, 인증시에 사용자 ID와 비밀번호를 파트너에게 노출하지 않을 수 있는 장점이 있다. (페이스북 계정을 이용한 웹 애플리케이션들을 보면 가끔, 페이스북 로그인 화면으로 리다이렉트되어 “XX 애플리케이션이 XX에 대한 권한을 요청합니다. 수락하시겠습니까?”와 같은 창이 뜨는 것을 볼 수 있는데, 페이스북 로그인 화면에, 사용자 ID와 비밀 번호를 넣고 페이스북은 인증이 되었다는 정보를 인증을 요청한 웹애플리케이션으로 보내서, 해당 사용자가 인증되었음을 알려준다. 이경우, 웹 애플리케이션은 사용자의 비밀번호를 알 수 없다. )
기본적인 OAuth의 원리는, 사용자 ID/PASSWD로 인증을 한 후에, access_token을 받아서, access_token을 이용해서 추후 커뮤니케이션을 하는 방식이다.

OAuth는 크게 용도에 따라 4가지 타입의 인증 방식을 제공한다.

  • Authorization Code 방식 - 주로 웹 애플리케이션 인증에 유리하며, 위에서 설명한 케이스와 같이 웹을 통해서 Redirect 하는 방식이다.
  • Implicit 방식 - 자바스크립트 기반의 애플리케이션이나 모바일 애플리케이션 처럼 서버 백엔드가 없는 경우 사용한다.
  • Resource Owner password credential 방식 - 인증을 요청하는 클라이언트에서 직접 ID와 PASSWD를 보내는 방식으로, (이 경우 위의 방식들과 다르게 서비스 제공자의 로그인창으로 리다이렉션이 필요 없다.) 클라이언트가 직접 ID,PASSWD를 받기 때문에, 클라이언트에 사용자의 비밀번호가 노출될 수 있어서 서버와 클라이언트를 같은 회사에서 제작한 경우나, 사용자의 정보를 공유해도 되는 1’st party 파트너등과 같은 경우에 사용한다.
  • Client Credential 방식 - 일반적인 애플리케이션 Access에 사용한다.

일반적으로 API를 3’rd party에 제공할 경우에는 Authorization Code 방식을, 자사의 API를 자사나 1’st party 파트너만 사용할 경우에는 Resource Owner password credential 방식이 좋다.

Mutual SSL

가장 강력한 인증 방법으로,클라이언트와 서버가 각자 인증서를 가지고 상호 인증하는 방식이다. 양방향(2-way)SSL 이라고도 한다. 이 경우에는 클라이언트의 인증서(Certificate)를 서버에게 안전하게 전송할 수 있는 메커니즘이 필요하다. 클라이언트가 접속했을때, Certificate를 네트워크를 통해서 전송하고, 서버는 이 인증서가 공인된 인증서인지를 확인하는 방법도 있고, 내지는 서버의 Admin Console등을 통해서 클라이언트가 사용하는 인증서 자체를 업로드 해놓는 방법등 다양한 방법이 있다.
Mutual SSL은 양쪽에 인증서를 사용하기 때문에, Man in the middle attack이 불가능하고, Packet을 snipping해서 보는 것 조차도 불가능 하다. (대신 구현이 다소 까다롭다.)

WhiteList 방식

서버간의 통신에서는 가장 간단하게 할 수 있는 방식이 서버가 API 호출을 허용할 수 있는 IP 목록을 유지하는 방법이다. (WhiteList 방식). 다른 IP에서 들어오는 API 호출의 경우 받지 않는 방법으로, 가장 구현이 간단하다. 방화벽이나 Reverse proxy 설정등으로도 가능하고, 필요하다면, VPN (Virtual Private Network)등을 이용할 수 도 있다.

프로토콜 레벨 암호화

HTTP 통신 프로토콜 자체를 암호화 하는 방식인데, SSL을 이용한 HTTPS가 대표적인 경우이다. API 디자인에서 HTTPS는 반드시 적용하는 것을 권장한다.
HTTPS는 앞에서도 잠깐 언급했듯이 Man in the middle attack에 취약한데 Man in the middle attack의 기본적인 메커니즘은 서버에서 보낸 인증서를 바꿔치기 해서, 클라이언트로 보내는 방식을 이용한다. (http://en.wikipedia.org/wiki/Man-in-the-middle_attack)
가능하면, 인증서 체크 로직을 클라이언트에 두는 것이 좋다. 인증서가 공인된 인증서인지, (또는 그 서버의 인증서가 맞는지를 Issuer등을 통해서 확인할 수 있다. 인증서에 있는 내용들은 기본적으로 중간에 해커가 바꿀 수 다 없다. Signing이 되어있기 때문에, 내용을 바꾸면 Singing된 Signature가 맞지 않는다.) attack

메세지 레벨 암호화

다음으로 JSON과 같은 메세지 자체를 암호화할 수 있는데, 앞서 설명해듯이 SSL을 사용하더라도, 중간에 인증서를 바꿔 치는 등의 행위를 통해서 패킷을 열어볼 경우, 메세지 내용을 노출될 가능성이 있기 때문에 이를 방지 하기 위해서, 중요한 메세지는 암호화하는 것을 권장한다.
이때 전체 메세지를 암호화 하는 것은 비효율적이며 특정 필드의 값만 필요에 따라서 암호화를 하는 것이 좋다.

무결성 관리 (HMAC)

메세지의 무결성 보장이란, 중간에 해커에 의해서 메세지가 변경할 수 없도록 하는 것이다. 기본적인 원리는 메세지에 대한 해쉬값을 계산해서, 보내서, 받는 쪽에서 받은 메세지를 가지고 똑같은 알고리즘으로 해쉬를 생성한후, 보내온 해쉬값과 비교하는 방법을 사용한다. 만약에 메세지가 변조가 되었다면,해쉬값이 일치하지 않기 때문에 메세지 변조 여부를 파악할 수 있다. 자세한 설명과 구현 방법은 http://bcho.tistory.com/807를 참고하기 바란다.

지금까지 간략하게 나마 REST API 설계 방식에 대해서 알아보았다.
자세한 자료들은 아래 참고 자료들은 참고하기 바란다.

참고 : http://info.apigee.com/Portals/62317/docs/web%20api.pdf
참고 : APICract Google groups https://groups.google.com/forum/?fromgroups#!topic/api-craft/
참고 : 마틴파울러의 ‘Glory of REST 향한 단계들’ http://jinson.tistory.com/190


새로운 문서가 업데이트 되었습니다.

REST API 이해와 설계 - #1 개념 잡기 http://bcho.tistory.com/953

REST API 이해와 설계 - #2 디자인 가이드  http://bcho.tistory.com/954

REST API 이해와 설계 - #3 보안 가이드  http://bcho.tistory.com/955



저작자 표시
신고

OAuth 2.0 based API 인증 메모

아키텍쳐 /Security & IDM | 2014.06.05 17:02 | Posted by 조대협


* Authroization Code

- Redirect base / 서버 백엔드가 있는 경우 사용 - 파트너사가 API를 사용하는 시나리오에 유리

* Implicit 

- Rediect base / 특히 Java script 처럼 서버 백엔드가 없는 경우 유용. Read Only 등에 사용

* Resource Owner Password Credential 

- Client Id, Secret을 앱에 넣은 후, Client Id/Password로 인증하여, access token을 발급 받는 방식으로, Authorization Server와 Resource Owner가 같은 서비스인 경우 유용함 (자사 API 제공에 유용)

* Client Crendetial


유용한 Link

  • 서버 구현체 : http://oauth.net/2/
  • http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified
  • node.js 모듈 - https://github.com/jaredhanson/oauth2orize
  • http://vinebrancho.wordpress.com/2014/05/19/oauth2-restapi-server-%EB%AA%A8%EB%B0%94%EC%9D%BC-%EC%95%B1%EC%9D%84-oauth2-0%EC%9C%BC%EB%A1%9C-%EC%A2%80-%EB%8D%94-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C/


저작자 표시
신고

'아키텍쳐  > Security & IDM' 카테고리의 다른 글

서버와 APNS(애플푸쉬서버)와의 보안 메커니즘  (3) 2014.10.07
OAuth 2.0 노트  (0) 2014.08.11
OAuth 2.0 based API 인증 메모  (0) 2014.06.05
Digital Signing의 개념  (0) 2014.05.21
Java keystore file  (0) 2013.09.27
SSL/TLS 관련 개념 링크  (1) 2013.09.24

Digital Signing의 개념

아키텍쳐 /Security & IDM | 2014.05.21 17:04 | Posted by 조대협


source : http://www.slideshare.net/simmikamra/digital-certificates?qid=2dec4a02-6d14-4694-9b6d-090a3da163b5&v=qf1&b=&from_search=1

저작자 표시
신고

'아키텍쳐  > Security & IDM' 카테고리의 다른 글

OAuth 2.0 노트  (0) 2014.08.11
OAuth 2.0 based API 인증 메모  (0) 2014.06.05
Digital Signing의 개념  (0) 2014.05.21
Java keystore file  (0) 2013.09.27
SSL/TLS 관련 개념 링크  (1) 2013.09.24
Security-애플리케이션 보안 1. 인증 방식 및 비밀번호 암호화  (0) 2013.06.09