마이크로서비스 Microservices (1) 아키텍처 소개

🗓 ⏱ 소요시간 6 분

주변에서 마이크로서비스 아키텍처(Microservices architecture; MSA)에 대한 이야기가 많이 들려옵니다. 마이크로서비스가 모든 것을 해결해줄 것처럼 이야기하는 사람이 있는가하면, 서비스 지향 아키텍처(Service-oriented architecture;SOA)랑 다를 게 없는 마케팅 용어에 불과하다고 폄하하는 사람들도 있습니다.

마이크로서비스 역시 장단점이 있는 하나의 기술일 뿐입니다. 마이크로서비스를 사용하면 서비스를 잘게 분리함으로써 애자일한 개발 환경과 점점 더 복잡해지는 애플리케이션에서 분명한 이점이 있습니다. 동시에, 서비스를 분리하면서 생기는 단점도 존재합니다.

모놀리식 아키텍처

카카오택시에 대항할 새로운 택시 앱을 만든다고 해봅시다. 필요한 요구사항에서 기능을 뽑아낸 후 다음과 같이 육각형 아키텍처(Hexagonal architecture)[1]를 이용해 다이어그램으로 표현했습니다. 육각형 내부에 있는 비즈니스 로직을 기준으로 외부 서비스(DB 액세스, 메시징, API 등)와 분리하기 위해 어댑터를 둔 모습입니다.

https://www.nginx.com/blog/introduction-to-microservices/

이렇게 만들어진 애플리케이션은 하나의 결과물로 패키징되어 배포됩니다. 이런 형태를 모놀리스(monolith) 또는 모놀리식 애플리케이션(monolithic application)이라고 합니다. 통으로 묶어서 배포되는 형태죠. 예를 들어 자바의 경우 웹 애플리케이션이라면 WAR 파일로 빌드되어 톰캣(Tomcat)이나 제티(Jetty)같은 WAS에 배포할 것이고, 일반 애플리케이션이라면 실행가능한(executalbe) JAR 파일로 묶여서 배포하겠죠.

장점

모놀리식 아키텍처의 장점은 ‘심플함’입니다. 모든 것이 하나의 프로젝트에 들어가있기 때문에 개발, 빌드, 배포, 테스트가 용이합니다.

  • 개발 환경과 개발 방법이 통일되어 있으므로 복잡할 게 없습니다.
  • 기존 IDE와 툴을 이용해 개발하기가 용이합니다(각종 툴이 싱글 애플리케이션 개발에 초점이 맞춰져 있음).
  • End-to-End 테스트가 쉽습니다.
  • 배포가 간편합니다(빌드 결과를 WAS에 올리기만 하면 됨).
  • 같은 애플리케이션을 여러개 두고 로드 밸런서를 앞에 두는 방법으로 쉽게 확장(scale)할 수 있습니다.

단점

하지만 이러한 장점은 애플리케이션이 간단하거나 규모가 작을 때의 이야기입니다. 시간이 지나면서 애플리케이션은 크고 복잡해집니다. 추가 요구사항, 새로운 기능들을 구현하면서 코드 양은 점점 늘어가면서 문제점이 드러나기 시작합니다.

  • 양이 늘어나고 복잡해지면서 대부분의 개발자가 전체를 이해하지 못하게 됩니다.
  • 코드 전체를 이해하고 있지 못하기 때문에 버그를 수정하기 어렵고, 수정하더라도 의도하지 않은 새로운 버그를 만들어내곤 합니다.
  • 애플리케이션 기동 시간도 늘어나고, 빌드 돌리는 시간도 한나절입니다. 이런 상태에서는 지속적인 통합(continuous integration;CI)과 지속적인 배포(continuous delivery;CD)는 불가능에 가깝습니다.
  • 여러 모듈이 함께 존재하기 때문에 각 모듈별 특성에 맞는 하드웨어 확장(scale-out)을 하기 어렵습니다.
  • 전체 프로세스가 하나의 프로세스에서 돌기 때문에 안정성에도 문제가 있습니다. 해당 프로세스에서 메모리 누수(memory leak)가 일어나거나 프로세스가 죽는 경우, 버그가 발생하는 경우 등 모든 영향을 한꺼번에 받습니다.
  • 새로운 기술, 언어, 프레임워크 등을 적용하기 어렵습니다. 부분적으로 들어내는 것이 어렵기 때문에 기술 노후가 올 때까지 냅두게 되고, 한참 뒤에야 차세대 프로젝트로 전체를 갈아엎게 됩니다. 이렇게 전체를 갈아엎는 것 자체가 상당히 경제적으로도 리스크적으로도 비용이 큰 일입니다.

마이크로서비스 아키텍처

마이크로서비스는 이런 문제를 해결해줍니다. ‘작은 서비스’라는 이름에서도 알 수 있듯이, 마이크로서비스는 하나의 큰 애플리케이션을 서비스 단위로 작게 나누고, 서비스들끼리 서로 통신하는 형태의 아키텍처 패턴입니다. 하나로 뭉쳐 있어서 문제니까 잘게 나눴다고 보시면 됩니다. 이미 많은 기업에서 모놀리스의 대안으로 마이크로서비스를 적용하고 있습니다.

앞에서 살펴본 예제에 적용해볼까요?

서비스

https://www.nginx.com/blog/introduction-to-microservices/

콜 관리, 고객 관리 등 서비스 단위로 나누고 각각의 서비스들은 API 형태로 제공됩니다. 각각의 서비스는 하나의 작은 애플리케이션처럼 배포가 가능합니다. 따라서 부분적으로 새로운 기능을 추가하거나, 새로운 기술을 적용할 수도 있습니다. 또한 부분적으로 장애가 발생하더라도 복구하는동안 해당 서비스와 연관이 없는 다른 서비스는 정상 동작합니다.

각 서비스는 서로 API 를 제공하고 이를 이용해서 서로 호출합니다. 각 서비스는 비동기(async)로 동작하고 메시지 기반으로 통신합니다. 사용자의 모바일 기기에서 REST API 로 서비스를 호출 시 직접 서비스로 가는 것이 아니라 중간에 API 게이트웨이를 거치게 됩니다. 여기서 API 게이트웨이는 부하를 분산시키는 로드 밸런싱, 캐싱, API 미터링, 모니터링 등 다양한 기능을 합니다.

이러한 마이크로서비스는 클라우드와 잘 어울립니다. 각각의 서비스가 가상머신(virtual machine; VM)이나 도커(Docker) 컨테이너에서 동작할 수 있습니다.

확장

사용자가 몰리면 서비스를 안정적으로 유지하기 위해 확장이 필요하죠. 스케일 방법에는 다음과 같은 세 가지 방법이 있습니다.

https://www.nginx.com/blog/introduction-to-microservices/

  • X 축 : 같은 서비스를 여러개로 복제
  • Y 축 : 서비스를 작게 나누기
  • Z 축 : 데이터 나눠서 저장

주로 위 세 가지 방법을 함께 사용하게 됩니다. 먼저 마이크로서비스에서는 같은 서비스를 여러개로 분리해놨습니다(Y축). 그리고 각 서비스마다 요청의 부하가 다른데, 모놀리스에서는 특정 서비스가 아니라 전체를 스케일할 수 밖에 없습니다. 이에 반해 마이크로서비스에서는 서비스가 나뉘어져 있기 때문에 부하가 몰리는 서비스 별로 복제해 스케일 아웃을 할 수 있습니다(X축).

아래 그림은 특정 서비스에서 요청이 많아졌을 때, 로드 밸런서가 해당 부하를 감지하고 해당 서비스를 EC2 인스턴스에 도커 컨테이너를 이용해 배포하는 모습입니다.

https://www.nginx.com/blog/introduction-to-microservices/

데이터

마지막 Z 축은 데이터를 나누어 저장하는 것입니다. 마이크로서비스에서는 DB도 서비스별로 나뉘게 됩니다. DB를 각각 사용하기 때문에 자신만의 스키마를 가지고 DB 종류도 다르게 가져갈 수 있습니다. 하지만 서비스가 동작하면서 여러 데이터에 영향을 미치기 때문에 각 서비스별로 중복되는 데이터도 생기고, 한 쪽에서 업데이트가 되었는데 다른 쪽에서는 업데이트가 되지 않을 수도 있습니다. 이러한 중복과 정합성 문제가 있지만 결합도를 낮추기 위해서 각각의 DB 를 사용합니다.

https://www.nginx.com/blog/introduction-to-microservices/

Microservices vs. SOA

표면적으로 마이크로서비스 아키텍처 패턴과 SOA 와 유사하게 보입니다. SOA 또한 애플리케이션을 서비스로 나눈다는 점에서 비슷합니다. 여기서 관건은 나뉜 서비스들을 어떻게 연결할 것이냐는 겁니다.

먼저 SOA 는 애플리케이션을 서비스로 나눈 후 ESB(Enterprise Service Bus)라는 미들웨어에서 연결하고 조립해서 만들어내는 아키텍처입니다.

https://byline.network/2016/12/1-490/

SOA 의 실패에는 ESB 가 큰 역할을 했습니다. SOA 의 인기에 힘입어 벤더들이 파는 다양한 솔루션과 장비들로 인해 SOA 를 구성하는 것이 어려워지고, 인기가 식어감에 따라 SOA 는 더 이상 발전하지 못했습니다. 하지만 마이크로서비스는 중앙집중적인 ESB 대신 REST API 또는 경량화된 메시징을 이용해서 각 서비스 중심으로 처리합니다.

엔터프라이즈 IT 업계에서 시작된 SOA 의 개념은 근래의 대형 인터넷 업체들을 중심으로 이어져 서비스와 API 기반의 MSA 로 정립되었습니다. 구축된 API 는 외부로 오픈해서 다른 서비스와 함께 더 큰 가치를 만들거나 판매할 수도 있습니다.

장점

애플리케이션을 서비스 단위로 나눠서 얻게 되는 장점을 정리하면 다음과 같습니다.

  • 서비스 별로 집중해서 독립적으로 개발할 수 있습니다.
  • 서비스 별로 독립적이기 때문에 소스를 이해하고 수정 및 유지보수가 쉬워집니다.
  • 서비스 별로 외부에는 API 만 노출되기 때문에 내부적으로는 어떻게 구성하든 상관없습니다. 따라서 각 서비스별 특성에 맞게 기술 스택을 결정할 수 있고, 새로운 기술을 적용할 수도 있습니다.
  • 서비스 별로 독립적인 배포 및 확장이 가능합니다.
  • 서비스 별로 특성에 맞는 리소스를 선택해 하드웨어를 구성할 수 있습니다.

단점

하지만 나누는 것이 무조건 좋은 것은 아닙니다. 보시면 아시겠지만 간단한 애플리케이션이라면 굳이 나눌 필요가 없습니다. 분산 환경이 되면서 서비스 간 통신, 분산 데이터 처리 등 없어도 될 일들을 만드는 꼴입니다.

  • 서비스를 나눠서 서비스 간 통신 방법이 필요합니다.
  • 서비스를 나눠서 서비스간 호출이 모놀리스보다 복잡합니다.
  • 서비스를 나눠서 데이터 중복이 발생할 수 있고 정합성을 보장하기 어렵습니다.
  • 서비스를 나눠서 테스트가 어렵습니다.
  • 서비스를 나눠서 특정 서비스가 실패하더라도 나머지 서비스는 유지되기 때문에 서비스가 실패했을 때를 고려해서 개발해야 합니다.
  • 서비스를 나눠서 배포하는 것이 복잡합니다. 서비스 디스커버리(Service discovery)[2]가 필요하고 배포를 자동화하기가 쉽지 않습니다.

결론

모놀리식 아키텍처와 마이크로서비스의 특징과 장단점을 살펴봤습니다. 마이크로서비스는 만능이 아닙니다. 장점을 극대화할 수 있을 때 사용하는 것이 맞습니다.

모놀리식은 하나로 묶여 있기 때문에 쉽고 간편한 대신 애플리케이션의 규모가 커지고 복잡해지면 관리하기가 어려웠습니다. 마이크로서비스는 이렇게 커진 애플리케이션을 독립적인 서비스 단위로 나눠서 유연하게 관리할 수 있지만 분산 환경에 따른 부가적인 기술과 리소스가 필요해 복잡해집니다.

  • 작고, 가벼운 애플리케이션은 모놀리식 아키텍처로!
  • 크고, 복잡하고, 장기적으로 운영되는 애플리케이션은 마이크로서비스 아키텍처로!

참고


  1. 1.애플리케이션을 레이어로 나누는 대신 인사이드와 아웃사이드로 나누는 아키텍처 패턴. https://dzone.com/articles/hexagonal-architecture-is-powerful 참고
  2. 2.분산 환경에서 각 서비스(노드)가 클라우드에서 동적으로 할당되어 배포되기 때문에, 각 서비스 찾는 기능이 필요하다. 이를 서비스 디스커버리라고 함.