기본 콘텐츠로 건너뛰기

Microservice 에 대한 나만의 정리 2

서론


원래 이번 포스트는 12 Factors App에 대해 정리를 해 보려고 했다.
저번 포스트가 좀 힘들어 이번엔 간단한 거로 해볼까 하는 생각과 최근 개발 방향을 요약해서 정리할 수 있지 않을까 싶어서였는데, 이전 포스트의 정리가 워낙 엉망이었던 것 같아서 다시 한 번 정리해볼까 하는 생각을 하게 되었다.

저번 포스트는 마틴 파울러 씨의 블로그 포스트를 기반으로 해서 정리를 해 보았는데, 한 달 전쯤 봤던 Devoxx 2015 세션 중 하나였던 Refactor your Java EE application using Microservices and Containers를 진행하셨던 Couchbase의 Vice President인 Arun Gupta 씨의 동영상이 기억이 났다.
해당 세션을 정리할 생각은 아니고 거기서 소개된 대부분 내용이 그보다 이전에 Dzone 에서 받아 놓았던 Getting Started with Microservices 라는 pdf에 정리되어있었던 것이 기억나서 그것을 정리해 보고자 한다.

참고로 Arun Gupta 씨의 위 동영상은 [여기] 에서 볼 수 있다.
(본문에서는 씨라는 존칭은 생략하고 정리하겠다.)

What are microservices?


마이크로서비스는 하나의 커다란 서비스를 느슨하게 결합 돼 있는 하나의 목적을 가지는 여러 개의 서비스로 나누고, cross-functional team에 의해 개발하고 운영을 하여, 최근 디지털 비즈니스에 있어 요구되는 빠르게 개발/유지보수 되면서도 품질이 우수한 시스템을 개발하자는 아키텍처적 접근 방식이다.


Key Characteristics of microservices


이전 포스트에서 봤던 특성들을 Arun Gupta 는 아래와 같이 정리하고 있다.

  1. DDD(Domain-Driven Design) : 마이크로서비스를 위해 기능을 분리해내는 데는 DDD가 많은 도움이 된다.
  2. Single Responsibility Principle : 객체지향 설계의 기본 원칙이지만, 마이크로서비스도 이 원칙을 기본으로 한다.
  3. Explicitly Published Interface : 정보를 생산하는 쪽의 서비스가 명확한 인터페이스를 공개하면, 그 인터페이스를 통해 수요자가 되는 서비스에서 사용하게 된다.
  4. Independent DURS (Deploy, Update, Replace, Scale) : 각 서비스는 독립적으로 배포되고, 업데이트되고, 치환되며 확장될 수 있다.
  5. Lightweight communication: 이전 포스트의 Smart endpoints and dumb pipes 의 내용이다. HTTP 기반의 REST, WebSocket 기반의 STOMP를 예로 들 수 있으며, 이 외에도 RabbitMQ라던가 ActiveMQ 등도 그 예라고 할 수 있겠다.

Benefits of microservices


그렇다면 마이크로서비스의 이점은 무엇일까? 
물론 아래의 이점은 마이크로서비스가 잘 구성되어 개발되었을 때 얻을 수 있는 이점들이다.

Independent scaling


각 서비스는 일반적으로 X축 확장으로 불리는 멀티 애플리케이션(또는 서버)의 확장과 Z축 확장(Partitioning 또는 Sharding)으로 불리는 확장을 독립적으로 할 수 있다.
(스케일링과 관련된 자세한 내용은 [여기] 서 확인해 볼 수 있다.)

Independent upgrades

개별적으로 배포할 수 있고 개별적으로 업그레이드가 가능한 특성을 갖는 것이 마이크로서비스다. 따라서 당연한 이점이라 하겠다.

Easy maintenance

약간의 논란이 될 수 있을 수 있을 것 같지만, 기본적으로는 하나의 기능에 국한하여 개발되어 있으므로 비즈니스 로직도 한가지의 기능에 국한될 수밖에 없다. 따라서 비즈니스 로직이 단순하므로 그에 대한 유지보수 역시 단순하다. 하나의 비즈니스 기능을 담당하므로 코드 또한 그 규모가 작게 유지되며 이로 인해서 유지보수가 단순해질 수 있다.

Potential heterogeneity and polyglotism 

개발자 또는 팀은 기술이나 언어를 매우 자유롭게 선택할 수 있다. 본인들이 담당하는 비즈니스 기능을 개발할 때 다른 인프라적인 또는 사내 공용 라이브러리 등에 대한 제약에서 자유로워지기 때문이다. 이 자유로움은 서비스가 된 후에도 유효하다. 더 나은 기술이나 더 나은 언어가 나타난다면 자유롭게 서비스를 refactoring 하거나 심지어 rewrite 할 수도 있다.

Fault and resource isolation

모놀리스 서비스는 하나의 서비스가 Memory leak이나 종료되지 않은 데이터베이스 커넥션이 쌓인다거나 하는 문제가 발생할 경우 전체 서비스에 영향을 받지만, 마이크로서비스는 오류 발생의 영향을 해당 서비스만 받게 된다. 나머지 서비스는 이런 에러들에서 벗어날 수 있고 이전 포스트에서 설명했듯이 우아하게 이런 에러들을 처리하기까지 해서 사용자들에게는 영향을 미치지 않게 된다.

Improved communication across teams

이전 포스트와 이번 포스트의 특성에서도 나왔지만, 마이크로서비스를 개발하는 팀은 cross-functional team이다. 즉 해당 비즈니스 기능을 서비스로 만들어내는 데 필요한 모든 인력이 있는 조직인 것이다. 따라서 모든 인원은 해당 비즈니스 기능을 만들기 위해서 노력한다. 당연히 조직 내 모든 사람이 서로 소통해서 비즈니스 기능을 구성하기에 쉬운 조직구조를 가지게 된다는 것이다.

Operational Requirements for microservices


그렇다고 마이크로서비스가 모든 문제를 해결해줄 Silver bullet 인 것은 아니라는 것을 Arun Gupta 도 이야기하고 있다. 진정한 성공에는 그만한 투자가 이루어져야 한다는 것인데 그렇다면 어떤 부분들이 있을까?

Service Replication

각각의 서비스는 결국 X축 확장과 Y축 확장이 필요하다.

Service Discovery

실제 마이크로서비스를 구현해서 사용하고 있는 애플리케이션들은 PaaS 와 같은 분산 시스템에서 돌아가는 경우가 많다. 일명 클라우드에서 서비스되는 경우가 많다는 것이다. VM이나 Container 기반으로 돌아가기도 하는 등 Immutable infrastructure 상에서 서비스가 운영되고 있다. 문제점은 언제 서비스가 어떤 시스템에 배포될지를 사전에 알 수 없는 경우가 많다는 것이다. 즉, 어떤 서비스가 어떤 아이피와 포트로 서비스될지 서비스가 실제 배포되기 전에는 알 수 없는 경우도 많다. 이런 문제를 해결하기 위해 등장한 것이 service registration과 discovery이다. 즉, 각 서비스는 구동되면서 본인에 대한 정보를 등록하고 다른 서비스들은 서비스 요청을 하기 전에 이 등록된 정보를 제공하는 서비스에 질의를 던져서 정보를 얻어서 요청하게 된다. 이 부분은 나중에 마이크로서비스를 구성하는 일반적인 구성들을 따로 다른 포스트에 정리해 볼 예정이다.

Service Monitoring

분산 서비스의 가장 중요하고 어려운 부분이 이 서비스 모니터링과 로깅 부분이라 할 수 있다.
이 부분에서 최근 가장 화제가 되는 오픈 기반 도구는 ELK(Elasticsearch + Logstash + Kibana)인 것 같다. 시스템 구성적으로나 개발 적으로나 이 부분이 가장 많은 투자가 이루어질 부분이지 않을까 싶다.

Resiliency

모든 소프트웨어는 무조건 오류가 발생한다. 이 세상에 오류가 전혀 발생하지 않는 소프트웨어가 있을까? 마이크로서비스는 모놀리스와 다르게 여러 개의 소프트웨어가 서로 협력하여 서비스하게 된다. 따라서 그 소프트웨어가 많아지면 많아질수록 더 많은 오류의 가능성이 생겨난다. 마이크로서비스는 오류가 해당 서비스 이외의 서비스에 영향을 미치지 않도록 설계되어야 한다. 따라서 오류를 어떻게 일어나지 않게 할 것인가도 중요하지만, 그보다 중요한 것은 오류를 어떻게 다룰 것인가다. 오류가 발생한 시스템에는 오류가 복구될 때까지 요청 가능 서비스에서 제외했다가 오류가 복구되면 다시 해당 요청이 이루어지도록 하는 처리가 필요하다. 보통은 이 부분을 Circuit Breaker 와 소프트웨어 기반의 로드밸런서가 담당하게 된다.

DevOps

최근 몇 년간 가장 많이 들은 이야기가 DevOps 아닐까?
마이크로서비스가 성공하기 위해서는 자동화된 빌드와 배포(CI/CD) 가 필수적이라 할 수 있다. (이 부분은 이전 포스트의 마틴 파울러도 이야기하고 있다. 너무 당연하다고 생각해서 설명은 간략했지만...) 마이크로서비스는 개별적으로 배포가 일어나고 업그레이드가 일어난다. 따라서 전체적인 조율을 할 수 있는 DevOps 적인 기반일 필요한 것이다. 내가 이해하는 바로는 이 기능은 각 팀에도 존재해야 하고 전사적으로 존재해야 하지 않을까 한다.

Good design principles for existing monoliths


Arun Gupta는 마틴 파울러와 다르게 모놀리스에서 점진적으로 발전하는 마이크로서비스를 주장하고 있다. 모놀리스에도 적용될 수 있는 디자인 원칙은 다음과 같다.


  • MVC
  • Well-defined API
  • 중복제거(DRY)
  • CoC 원칙 (Clash of Clan 이 아니다)
  • 데메테르의 법칙(Law of Demeter) : 설명은 [여기]를 참고
  • DDD
  • YAGNI(You Aren't Going to Need It) : 필요하기 전까지는 만들지 말라.

Microservices Design Pattern


마이크로서비스에도 패턴이 있을까? 마이크로서비스라는 것은 대상이 되는 프로젝트에 따라서 정말 다양한 변형이 만들어질 수 있는 아키텍처라고 생각한다. 따라서 정확한 정답도 없다. 그래서 마이크로서비스가 아직도 나에겐 어려운 것일지도 모른다.

다만 일반적인 패턴들이 존재하기는 한데, 그 부분은 아래의 그림들이 좋은 참고가 되지 않을까 생각한다.

패턴들은 이름과 그림만 소개한다. 자세한 소개는 내가 허접스럽게 설명을 하는 것보다는 [여기]를 참고하는 것이 더 현명한 선택이지 않을까 싶다.

Aggregator pattern




Proxy pattern


Chained pattern


Branch pattern


Shared resources


Asynchronous Messaging pattern



결론


Arun Gupta 는 이외에 모놀리스를 마이크로서비스로 리팩토링하는 것에 대한 간단한 설명은 있으나, 이 부분은 되도록 서론 부분의 Arun Gupta의 동영상을 보는 것이 더 좋을 것 같다. 이유는 나 자신도 마틴 파울러의 생각처럼 모놀리스를 마이크로서비스로 리팩토링을 진행하는 것에는 찬성하지 못하기 때문이다. 자칫하면 더 어지러운 서비스가 될 수 있다고 생각한다. 단, 잘 설계된 모놀리스 애플리케이션을 가지고 있는 회사라면 마이크로서비스로의 점진적인 리팩토링도 충분히 가능할 것 같다.

만약 이글을 본 분 중에 마이크로서비스를 도입하고 싶다면, 애플리케이션의 구조가 어떻게 되어있는지를 차분하게 바라볼 필요가 있을 것 같다. 서비스별로 잘 구조화되어있고, 서로 간의 관계도 역시 명확하게 잘 설계되어있다면, 서론에서 소개한 동영상을 꼭 한번 보시고 진행하시는 것을 추천해 드린다.

이전의 포스트가 너무 개념적이어서 좀 더 요약이 잘 되어있는 Arun Gupta의 개념을 정리하고 싶어서 이 포스트를 시작했다. 결국 아직까지 정확한 개념을 이해하지 못한 탓인지 아니면 내 정리의 기술이 좋지 않아서인지 약간은 어수선하고 덜 정리된 포스트로 마무리를 하는 느낌이다.

혹시 이글을 읽고 뭔가 마이크로서비스의 개념을 잡고 싶으셨거나 도움을 받기 바랬던 분들이 있다면 송구스럽다.

원래 이 포스트는 2015년의 마지막 포스트로 쓰고 있었는데, 약간의 사고로 2016년의 첫 포스트가 되고 말았다. 다음 포스트에서 12 Factors App 을 정리하고 이젠 실제적인 마이크로서비스를 구성하는 것에 관한 포스트들을 정리해 볼까 한다.




댓글

이 블로그의 인기 게시물

경력 개발자의 자기소개서에 대해서...

갑자기 뜬금없이 이런 글을 쓰다니 무슨 생각이야? 라고 생각하시는 분들이 있을지도 모르겠네요. 뜬금없음에 대한 변명은 잠시 접어두고 일단 오늘 쓰려고 하는 글을 시작해볼까 합니다. 개발자로 대충 16년을 그럭저럭 보내왔습니다. 시대적 상황으로 5년 차쯤에 대리로 처음 팀장을 시작했으니, 일반 개발자로 산 시간보다는 어쨌건 프로젝트 또는 팀의 리더로 산 시간이 더 많았던 것 같습니다. 그 기간 동안 남들보다 좀 심하게 회사를 많이 옮겨 다니다 보니 꽤 많은 면접을 볼 수 있는 경험이 있었고, 또 옮긴 회사가 대부분 팀을 리빌딩하는 곳이었다 보니 꽤 많은 채용절차에 관여할 기회가 있어서 어린 나이부터 비교적 많은 이력서를 검토했고 면접관으로도 여러 사람을 만날 수 있었습니다. 처음 면접을 보러 다니던 시절의 제 이력서의 자기소개서는 항상 "19XX년 봄 XX업계에 종사하시던 아버님과 집안일에 헌신적인 어머니의 유복한 가정에 1남 1녀의 막내로..." 로 시작되었습니다 (이 문장에 향수를 느끼시는 분들 많으실 거예요. ^^). 경력이 5년이 넘은 어느 날 도대체 이 문장을 왜 써야 하느냐는 의문이 생겨서 조금 바꾸긴 했습니다만, 그 뒤로도 꽤 오랜 세월을 이런 자기소개서가 항상 제 이력서에 붙어있었죠. 요즘 누가 저런 식으로 자기소개서를 써? 라고 생각하시는 분들 많으실 거로 생각해요. (대신 요즘은 대학 시절의 봉사활동이나 해외연수 이력이... 뭐 어차피 그놈이 그놈입니다.) 저런 자기소개서를 써야 한다는 것이 어디서 어떻게 시작된 것인지는 몰라도 회사를 그만두기 전인 2년 전까지도 약간의 표현은 다를지 모르지만 비슷한 문장으로 시작하는 자기소개서를 이력서에 첨부해서 보내는 지원자들을 볼 수 있었습니다. 이제 제가 뜬금없는 이런 글을 쓰게 된 이유를 밝히고 계속 진행해야겠네요. 블로그에 올릴 글을 준비하는 일이 생각보다 힘들어요. 블로그에 올리려고 준비한 주제에 맞는 소스를 작업하고 거기에 글을 입히다 보면 가끔

Springframework 5에서 바뀌는 것들에 대한 간단 정리 및 생각

Spring framework 5 에 대해 많은 분이 기대와 두려움을 가지고 계시지 않을까 생각합니다. 특히 기대를 하고 계신 분들은 Reactive Programming 지원을 기대하고 계시지 않은가 생각이 드는데요. 7월 초에 John Thompson 이란 분이 D-Zone에 아주 깔끔하고 멋지게 정리를 잘해서 글을 쓰셨더라구요. 해당 글은  https://dzone.com/articles/whats-new-in-spring-framework-5 에서 확인을 하실 수 있습니다. 혹시 Spring framework 5에서 달라지는 내용의 좀 더 자세한 내용이 필요하신 분들은 Spring framework github의 wiki 를 참고하시면 됩니다. 본 포스트는 언제나 그렇듯이 윗글에 대한 번역이 아닙니다. 그저 윗글을 다시 정리하면서 제 생각을 한번 정리해 놓은 포스트입니다. Spring framework 5는 현재 5.0.0.RC2(2017.07.23일 기준)까지 릴리즈된 상황입니다. Spring framework 5에서 크게 변화하는 내용을 John Thompson은 8가지로 깔끔하게 정리해주고 있습니다. 1. JDK 지원 버전의 업데이트 5버전은 원래 JDK 9 버전의 지원을 위해서 시작됐던 프로젝트로 알고 있는데 맞는지는 모르겠네요. JDK 9의 Release가 늦어져서 Spring framework 5가 먼저 Release 될 것으로 보이지만, JDK 9가 Release가 되면 언제건 적용할 수 있다고 합니다. 좀 아쉬운 부분은 JDK의 최소 버전은 JDK 8이라는 부분이 아닐까 싶네요. 이 때문에 Spring framework 5에 무관심한 분들도 많으실 거라고 생각합니다. 지금 진행하는 프로젝트는 JDK 8을 기반으로 합니다만, 최근까지 다니던 회사의 경우는 JDK 7까지가 업그레이드 한계였던 회사였습니다. 아마도 JDK 업그레이드를 쉽게 못 하시는 회사들이 많으니 "나랑은 관계없는 얘기군"

Gradle 을 이용해서 Multiproject 를 구성하는 방법 (중 하나)

개요 회사에서 Gradle 을 이용하게 된 이래로 계속 Multi-project 형태로 설정하여 진행을 해 오고 있다. 매번 멀티 프로젝트 형태로 만들어지고 있는 회사의 프로젝트들이다 보니 그때마다 다시 이전 빌드 스크립트를 보면서 만드는데 프로젝트들이 복잡하다보니 필요없는 설정들까지 복사해서 쓰고 있는 부분들이 있어서 한번 정리를 했으면 하고 있었다. 가장 기본적인 상태의 멀티프로젝트용 build.gradle 에 대한 여러가지 방법 중 한가지라 생각하고 참고가 된다면 좋겠다. 요구사항 기본 요구사항은 다음과 같다. 1) 멀티프로젝트는 디렉터리를 기반으로 아래와 같이 그룹으로 만들어 질 수 있어야 한다.   - Shared : 다른 프로젝트에서 Dependency로 추가될 수 있는 공통 라이브러리를 포함하는 라이브러리 모듈 그룹   - Web : Front 모듈 그룹   - Server : 주로 어플리케이션 간의 설정 등을 관리하는 Server 모듈 그룹   - Service : Web API 서버 모듈 그룹 2) 모든 Subproject 들은 Java project 이며, 프로젝트 명은 "모듈그룹명-모듈명" 으로 만든다. 즉, Server 모듈의 configuration-server 모듈이라면 server-configuration-server의 형태로 만들어지면 된다. 이후에 작업된 모든 내용은 Ubuntu 14.04 OS와 IntelliJ IDEA 15에서 작업되었다. (윈도우즈와 이클립스에서도 동일한 내용을 동작이 될 것으로 보인다. 다만, 테스트되지 않았을 뿐이다) Main Gradle Script 작업 1) 파일 구성   - build.gradle : gradle script 파일   - settings.gradle : sub project 관리를 위한 파일 2) build.gradle 파일 작성   - 우선은  프로젝트 기본 정보로 group 정보와 version 을 설정한다. 본인의