서론
원래 이번 포스트는 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 는 아래와 같이 정리하고 있다.
- DDD(Domain-Driven Design) : 마이크로서비스를 위해 기능을 분리해내는 데는 DDD가 많은 도움이 된다.
- Single Responsibility Principle : 객체지향 설계의 기본 원칙이지만, 마이크로서비스도 이 원칙을 기본으로 한다.
- Explicitly Published Interface : 정보를 생산하는 쪽의 서비스가 명확한 인터페이스를 공개하면, 그 인터페이스를 통해 수요자가 되는 서비스에서 사용하게 된다.
- Independent DURS (Deploy, Update, Replace, Scale) : 각 서비스는 독립적으로 배포되고, 업데이트되고, 치환되며 확장될 수 있다.
- 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 을 정리하고 이젠 실제적인 마이크로서비스를 구성하는 것에 관한 포스트들을 정리해 볼까 한다.
댓글
댓글 쓰기