MSA(Micro Service Architecture)로의 전환
Prolog
좋은 서비스란 무엇일까요? 사용자에게 필요한 기능들을 제공하고, 피드백을 분석하고, 분석된 데이터를 기반으로 또 다른 편리한 무엇인가를 제공하면서 점점 성장해 나가는 것이 아닐까 생각합니다. 작은 서비스일 때에는 전통적인 3-Tier Architecture를 통해 서비스를 제공해도 충분하였으나 대규모 서비스로 거듭나기 위해서는 시스템 복잡도를 낮추고, 유연하게 확장할 수 있으면서도 생산성 또한 좋은 또 다른 무엇인가가 필요하게 되었습니다.
마이리얼트립도 서비스 규모가 빠른 속도로 성장하고 있어서 좀 더 유연하게 확장 가능한 Architecture가 필요하게 되었습니다.
What about?
지난 수십여 년간 프로그래밍 언어 분야에서는 기계가 이해하는 방식이 아닌 사람이 이해할 수 있는 방식으로 좀 더 쉽고 확장성 있게 개발할 수 있도록 진화되어 왔습니다. 그중 하나가 객체지향 프로그래밍(Object-Oriented Programming, OOP)입니다.
OOP와 유사하게 Architecturing 관점에서는 SOA(Service-Oriented Architecture), EDA(Event-Driven Architecture), MSA(Micro-Service Architecture)등의 개념이 소개되었고 복잡도를 낮추고 확장성 있는 시스템을 구축하기 위해 모든 기능이 하나의 Component에 모여있는 Monolithic 방식에서 MSA로 전환되고 있습니다.
이 아티클에서는 마이리얼트립에서 도입하려고 하는 MSA(Micro-service Architecture)에 대해서 이야기해 보려고 합니다.
What’s Micro Service Architecture?
이름에서 짐작할 수 있듯이 MSA는 작은 서비스들을 모아서 커다란 서비스를 구성하는 것을 의미합니다. 다른 말로 설명해 본다면 “작고, 독립적으로 배포 가능하며 개별의 기능을 수행하는 프로덕트들로 구성된 시스템”이라고 정의해 볼 수 있습니다.
Monolithic vs. MSA
MSA를 도입을 고려해 보기 위해서는 기존에 사용되었던 Monolithic Architecture와 MSA의 장단점을 비교해 볼 필요가 있습니다.
Pros and Cons of Monolithic
Monolithic Architecture는 전통적인 3-Tier Architecture 형태로 구성이 되고 Application Tier에 대부분의 Business Logic이 들어가게 됩니다. 이로 인한 장단점은 아래와 같습니다.
Advantages
Simple to develop : Component 간의 통신 등을 고려하지 않아도 되기에 초기 개발이 쉽습니다.
Simple to test : 이 기종 간의 통신이 없기에 테스트가 용이합니다.
Simple to deploy : 하나의 모듈만 배포하면 됩니다.
Simple to scale horizontally : Scale-out을 통해 Capacity 확장이 용의 합니다.
Drawbacks
Limitation in Size : Scale-out을 통해 Capacity를 늘릴 수 있으나 Data Layer의 Capacity를 넘지 못하는 한계가 있습니다.
Complexity : 서비스가 확장되고 다양한 기능이 추가될수록 모듈의 복잡도는 높아집니다.
Entire deployment : 작은 기능 하나를 배포하기 위해서도 전체 모듈이 배포되어야 합니다.
Slow warm-up time : 전체 모듈을 배포하기에 Application의 구동에 시간이 오래 걸립니다.
Hard to continuous deploy : 상호 연관 관계가 깊은 모듈로 인해 대규모 조직에서 개발하는 경우 변경 사항 배포를 지속해서 유지하기가 어렵습니다.
Reliability : 작은 버그 하나가 전체 시스템에 영향을 미칠 수 있습니다.
Coupling : 하나의 컴포넌트에 모든 기능이 포함되어 있기에 모듈 간의 결합도가 높습니다.
Barrier to adopt new technology : 단일 시스템이기에 확장을 위한 새로운 언어 및 기술을 도입하기 어렵습니다.
Pros and Cons of Micro-service Architecture
“작고, 독립적으로 배포 가능하며 개별의 기능을 수행하는 프로덕트들로 구성된 시스템” Micro-service Architecture는 Monolithic Architecture와는 다른 장단점이 존재합니다.
Advantages
Product based : MSA를 구성하는 Component는 Project가 아닌 Product 단위입니다. 단위 Component에 집중하기 수월합니다.
Single Responsibility : 단일 책임 원칙을 기반으로 설계가 되고 큰 문제를 작은 단위 문제로 나누어 해결할 수 있도록 도와줍니다.
Simplicity, Loosely Coupling : 작은 단위 문제를 해결하기 위한 Component들의 모음이기 때문에 단위 복잡도가 낮아집니다. Product의 구현은 Encapsulation 되고 연동은 Interface 정의 기반으로 결합하기에 낮은 결합도를 가집니다.
Productivity and Speed : Product의 단위 복잡도가 낮기 때문에 생산성이 좋습니다.
Flexibility, Adopting New Technology : Divide & Conquer 방식의 접근 방식을 활용하고 문제 해결에 적합한 기술을 사용할 수 있습니다.
Scalability : Product 단위로 독립적인 Scale-out을 할 수 있습니다.
CI/CD : 지속적인 통합과 지속적인 배포를 통해 서비스 안정성을 확보할 수 있습니다. 자동화된 통합 테스트/배포 환경을 구축할 수 있는 기반을 제공합니다.
Cross-Functional Teams : Functional Team을 구성하여 단위 서비스를 만들 수 있습니다.
Drawbacks
Distributed System : 분산 환경이기에 고려해야 할 부분들이 많습니다. Eventual Consistency에 대한 고려가 필요할 수 있습니다.
Testing : 여러 개의 Product가 조합되어야 Integration Test가 가능합니다.
Roll-out the Changes : 여러 개의 Product가 서비스를 구성할 때 배포 순서 등의 고려가 필요합니다.
Cost : 분산 시스템을 구성하기 위한 Minimum Set이 Monolithic보다는 많이 필요합니다.
Why Micro-service Architecture?
Monolithic과 MSA의 장단점을 비교한 내용에서 언급한 것과 같이 Monolithic 기반의 Architecture는 MVP(Minimum Value Product)를 빠르게 개발하기에는 적합한 Architecture이지만 서비스 규모가 커지면 확장성이 떨어지고 복잡도가 높아지게 됩니다.
이에 마이리얼트립에서는 확장성을 높이고 복잡도는 낮추기 위해 MSA 형태로 Architecture를 변경하기로 하였습니다.
Implementation Patterns
MSA로의 전환을 하기 위해서는 아래와 같이 진행되고 Architecture 구성을 위한 몇 가지 패턴이 존재합니다.
- 도메인 업무 단위의 Component로 서비스를 분리하고 Component 간 강결합 제거
- 의존성이 존재하는 Component 간의 Interface 정의
- Component 간의 통신을 Object/Method Call, IPC(Inter-process Communication) 등의 방식에서 REST(Representational State Transfer), gRPC(Remote Procedure Call), Thrift, SOAP(Simple Object Access Protocol) 등의 원격지 API 호출 방식으로 전환
Networking
단위 Component간의 통신에는 아래의 2가지 패턴이 주로 많이 사용됩니다.
- API Gateway Pattern
Client 서버로부터 Target 서버로의 접속을 위한 정보 관리 기능 제공을 위해 Service Discovery Layer가 필요합니다. 접속 정보 관리 및 Authentication Filter 등의 역할을 API G/W에 위임하고 Client 서버는 API G/W의 EndPoint와 통신을 하면 API G/W에서 Reverse Proxy 형태로 서비스를 제공하는 패턴입니다.
- Event Driven Pattern (Message Queue Centric Workflow Pattern)
Asynchronous 방식으로 단위 기능이 수행될 때 N개의 Component API들을 호출하고 결과값을 조합하는 경우나(Callback) 수행된 결과값을 N개의 Component에 통지해야 할 때(Broadcasting) 사용하는 패턴입니다.
Client 서버에서 Message Queue로 Payload를 Publish하고 Target 서버에서는 해당 Payload를 Consume 하는 방식입니다.
Authentication 등의 절차가 불필요할 경우 MQ를 이용하여 API G/W의 역할을 대행하는 구조로 사용되기도 합니다.
Message Queue에 장애가 발생할 경우를 대비하여 Dead Letter Queue 등의 대비책이 마련되어야 합니다.
Infrastructure
- Container Service(Docker, LXC)
MSA를 도입하게 되면 모든 문제를 해결하기 위해 Divide & Conquer 전략을 따르게 됩니다.
매우 작은 단위의 Component로 나뉘고 HA 구성 등을 하다 보면 리소스 낭비가 발생할 수도 있고 불필요한 Network Traffic이 유발되어 성능에 이슈를 발생시킬 수 있습니다.
이럴 경우 Container 기반으로 동일 장비에 여러 Component를 배포하여 외부 통신이 아닌 내부 통신으로 처리해 성능을 개선할 수 있습니다.
예로 Log Aggregator 와 같은 모듈을 개별 로그마다 외부 API 호출하는 방식이 아닌 Side-Car 형태로 동일 서버에 구성하여 Chunk 단위로 수집 서버에 전송하는 방식이 있습니다.
- Container Orchestration(Kubernetes, Apache Mesos)
Container 기반으로 서비스를 구축하더라도 Scale-out 여부를 판단하는 Threshold는 Host OS의 것에 의존하게 되기에 단일 Instance 상에서 단일 Container가 동작하는 환경에서는 리소스의 낭비가 발생할 수 있습니다.
이러한 환경에서 서비스 운영이 되어야 하는 경우 K8S 등의 Container Orchestration Framework를 도입하여 리소스 사용을 효율화 할 수 있습니다.
Conclusion
문제 해결이 필요한 곳에 적합한 기술을 활용해서 비용 낭비를 줄이고 원하는 GOAL을 달성하는 것이 엔지니어가 수행해야 할 임무라고 생각합니다.
마이리얼트립에서는 낮은 복잡도와 더 유연하게 확장해 나갈 수 있는 시스템 기반을 마련하기 위해 기존 Ruby on Rails 기반 Monolithic Architecture로 구현된 서비스를 점진적으로 MSA 기반으로 개편해 나가고 있습니다.
Simplicity, Productivity, Flexibility, Scalability의 강점을 가지고 있는 Micro-service Architecture 도입에 관심을 가지고 계신 분들에게 도움이 되기를 바라며 이상으로 MSA로의 전환에 대한 글을 마무리합니다.
아울러 마이리얼트립은 좋은 동료분들을 계속해서 모시고 있습니다!
기술을 바탕으로 여행시장을 혁신하는데 관심 있는 분들은 아래의 채용 페이지를 방문해 주세요.