[Microservice] MSA?

Dev·2022년 5월 26일
0

은총알은 없다. 마이크로 서비스 구조가 만능이 아니다. 마이크로서비스는 피치 못하게 모놀리틱 서비스보다 '복잡성'을 갖는다. 모놀리틱에서는 필요 없는 통신이 추가되고, 분리된 데이터 동기화와 같이 배포시 신경써야할게 늘어날 수도 있다.

1. 적절한 MSA 구조에서의 장점

분리된 서비스들이 독립적으로 나아간다.

  • 조직부합성
    • 콘웨이 법칙과(조직이 설계한 시스템 디자인은 해당 조직의 커뮤니케이션 구조를 따른다.) 같이, 시스템 아키텍처가 조직에 맞게 구성되어 협업이 수월해진다.
  • 확장성
    • 모놀리틱 구조와 달리, 전체 서비스가 아닌 필요한 서비스만 확장이 용이한다.
  • 회복성
    • 다른 서비스와 독립적이라면, 다른 서비스에서 장애가 발생해도 장애가 전파되지 않게 할 수 있으며, 문제 발생시 롤백도 필요 부분만 수행하여 장애 영향도가 적다.
  • 배포 용이성
    • 다른 서비스와 독립적이라면, 다른 서비스 신경쓸 필요 없이 배포를 원하는대로 가능하다. 즉, 비지니스 요구사항에 맞게 빠르게 독립적으로 배포할 수 있다.
  • 대체 가능성 & 조합성
    • 작은 서비스로 구성되니, 쉽게 다른 컴포넌트로 대체 가능하며(리팩토링도 용이) 이러한 컴포넌트끼리 조합도 쉽게 할 수 있다.
  • 기술 이기종성
    • 작은 서비스로 구성되니, 그 서비스(팀)에 맞는 기술 ex) 언어, db, infra 등을 핏하게 맞출 수 있다.

2. 적절치 않은 MSA 구조에서의 단점

  • 독립적인 서비스들 사이에 협업을 통해 비지니스가 처리되다 보니 시스템이 기본적으로 복잡해진다. 운영 측면에서 한 비지니스 프로세스의 파악을 위해 여러 서비스들의 존재를 알아야하고 그들 사이에서 발생하는 협업들에 대해서도 파악해야 한다. 즉, 운영영의 어려움을 가져온다. 물론 독립적인 서비스라면 BEST
  • 분리된 서비스들이 하나의 테이블을 건드리는 상황에서, 테이블에 이상한 데이터가 발생해도 어느 서비스 때문인지 파악이 어렵고, 하나의 트랜잭션으로 묶기 또한 힘들다. 즉 데이터 동기화의 어려움이 있다.
  • MSA 구조는 분산 환경이기 때문에 강력한 트랜잭션 일관성을 제공하기 힘들다. 최종적인 일관성 제공을 위해선 다른 매커니즘을 갖고와야한다.
  • 하나의 기능이 여러 서비스에 분산되어, 하나의 기능을 유지보수하기 위해선 여러 서비스를 건드려야 하고, 이는 곧 개발 시간이 늘어남과 동시에 사람인지라 수정해야될 부분을 빠트리는 등 예상치 못한 버그로 이어진다.
  • 의존성이 섞여 있는 컴포넌트는 여러 컴포넌트가 묶여 있으니 배포도 동시에 일어나야하는 상황이 발생하여, 관련된 여러 서비스간 배포 시간을 맞추는 등 불편함이 생긴다. MSA 구조에서 독립 배포의 장점을 잃어버리는 꼴이다.
  • 분리된 서비스들간 테스트 또한 쉽지 않다. 테스트를 하기 위해선 의존성이 있는 서비스를 미리 확인해야 한다. 의존성있는 서비스가 정상적이지 않은 경우 테스트가 힘들다.
  • 디버깅도 힘들 수 있다. 시스템 문제 발생시 모놀리틱 구조에선 서버 하나에 대한 문제 원인을 파악하면 되지만 MSA 구조는 관련된 모든 서비스를 일일히 살펴봐야되며, 통합 로그 관리 시스템이 없다면 하나하나 수동으로 서버 들어가서 파악해야된다.
  • 이정도면 하나의 시스템을 억지로 찢은 느낌이다. 물론 처음엔 서비스들이 적절히 분리되있으나, 일정 압박으로 괜찮은 아키텍처 고려없이 의존성이 중구난방으로 펼쳐지며 복잡한 구조를 갖게되는 경우도 있다.
  • 물론 모놀리틱 서비스가 가지는 한계도 있다. 장애의 퍼짐을 막기 힘들고, 수평 확장밖에 못하는 한계도 있다. 성능을 올릴 때 로드 밸런서를 두거나, 모든 서버를 증가시킬 수밖에 없다.
  • 결국, 분산시스템이 가지는 복잡성을 해결해야 MSA 구조의 장점을 끌어올릴 수 있다. 이것만 해결한다면 앞서 말한 강력한 장점을 갖고 올 수 있다. 흑백논리처럼 무조건 어디가 좋다고 생각하지말고 도메인/상황에 맞게 선택하자.

참고) 모놀리스 구조

  • 모놀리틱 서비스는 단일 프로젝트에 모든 코드가 모여있는데,
  • 시스템 구조가 간결하고, 빠르게 구축할 수 있다. 처음부터 MSA 구조를 선택하는 것이 아닌 모놀리틱 서비스로 나아가되, 추후 의존성을 분리하고, 모듈을 분리하는 방향으로 나아가자.
  • 테스트 및 배포 파이프라인 모놀리틱보다 구성이 간단하며, 인프라스트럭처 구축과 운영이 용이하다.

3. 코드의 응집과 결합

  • 기능만 돌아가면 되지, 왜 SW 디자인(코드 구조)을 신경쓸까? 성능도 중요하지만, 결국 소비자에게 제공하는 비지니스 변경을 빠르게 반영하기 위해서다. 빠른 서비스 반영은 곧 수익으로 이어진다.
  • SW는 태생적으로 신경쓰지 않는다면 자연스럽게 구조는 복잡해진다. 이러한 복잡도를 잡는데 코드의 응집과 결합을 다스리는 것이 먼저다.
  • Monolitic -> MSA 구조로 가는데 실패하는 가장 큰 이유 중 하나는 내부 구조가 복잡하기 때문이다. 따라서 코드의 복잡도를 잡는것이 첫번째이다.
  • 변화에 성격과 비용(개발자 인력/시간)을 고려해야 하며, 밸런스에 맞춰 응집도를 높이고, 결합도를 낮추는것이 목표다. 만약 서비스를 작게 쪼개면 응집도는 높아지겠지만, 모듈간 결합도가 커지고 // 서비스를 크게 묶으면 모듈간 결합도는 낮아지지만, 응집도는 낮아진다. 결국 이들간의 밸런스를 맞출 필요성이 있다.
    • 코드의 응집
      • 시스템의 변경이 필요할 때, 하나의 요소에서 변하는 정도
      • 어느 부분이 변경될 때, 해당 부분의 전체가 변한다면 응집도가 높은거고, 일부만 변경되면 요건 응집도가 낮다할 수 있다.
    • 코드의 결합
      • 두 개 이상의 요소가 있을 때, 하나의 변경이 또 다른 하나의 변경에 미치는 정도이다.
      • 변경했을 때 다른 컴포넌트들도 많이 변경되면 결합도가 높다할 수 있다.

더 좋거나 나쁜 아키텍처는 없고, 시스템이 처한 환경에 따라 조건이 다르고, 이를 보고 유연하게 구조를 판단한다. 이때 시스템은 지속적으로 변하고, 이에 적응할 수 있는 아키텍처를 고려하자.

4. 유연한 시스템을 위한 조건

좋은 아키텍처는 시스템이 모노리틱 구조로 태어나서 단일 파일로 배포되더라도, 이후에는 독립적으로 배포 가능한 단위들의 집합으로 자연스럽게 성장하고, 또 독립적인 서비스나 마이크로서비스 수준까지 바뀔 수 있도록 만들어져야 한다. 또한 좋은 아키텍처라면 나중에 상황이 바뀌었을 때 이 진행 방향을 거꾸로 돌려 원래 형태인 모노리틱 구조로 되돌릴 수도 있어야한다. by clean architecture 이말의 핵심은 결국 의존성을 잘 관리한 코드 구조는 Monolitic <-> MSA 의 전환이 자유로움을 의미한다.

[1] 모듈화

  • 단일 시스템이 커졌을 때 boundary context(domain의 경계) 와 같이 특정 조건에 맞게 경계를 두어 분리한다. 예를 들어 java에선 package로 경계를 구분한다.
  • private/public method로 외부에 공개하지 않은것들을 구분하고, 모듈화가 잘 되있으면 시스템을 볼 때 전체를 볼 필요가 없이 필요한 부분만을 확인하여 개발 생산성이 증가한다.
  • 즉, 내부 서비스를 숨기고, 외부랑 통신할 때는 공개된 API로 통신한다.

[2] 아키텍처 구조

  • Layered, Domain, Union, Hexagonal 아키텍처 등 다양하게 있다. 점차 아키텍처 구조 패러다임은 관심사의 분리를 통해 애플리케이션 핵심을 외부 연동 모듈과 분리시킨다. 이렇게 분리된 영역은 필요에 따라 어렵지 않게 '변경'이 가능해야한다.
  • 즉, 애플리케이션 핵심은 코드의 영향을 최소화하고, 변경이 잦은 외부 컴포넌트는 쉽게 바꿔치기(통합/변경)할 수 있다. 이에 따라 테스트 하기 쉽고, 변경을 빠르게 수용할 수 있다. 이로써 고객에게 비지니스 변경을 빠르게 제공할 수 있는지 고민하자.
  • ex) Layered Architecture는 시스템 규모가 커지면 계층 내부에 복잡도가 증가하며 && 또한, 모든 계층의 변경이 일어날 여지가 있다. 이에 따라 도메인을 기반으로 분리하고, 내부적으로 계층을 분리하는 아키텍처로 변경한 사례가 있다.
  • 관심사에 따른 모듈화
    • 수직적 관심사 : 비지니스와 응용 프로그램에 특화된 기능(핵심 도메인)을 중점으로 관심사를 혹은 경계를 분리한다.
    • 수평적 관심사 : 로깅, 보안 등 공통적인 저수준 기능으로 비지니스와 무관하게 공통 모듈을 제공한다. 재사용성이 목표다.
  • 잘 모듈화(ex-package 구분) 했다면 이제 모듈 사이의 경계를 넘어오지 못하게해야한다. ex) 컴파일러, 외부 의존성 관리 도구, private/protected/public, 수기, 수동 등 다양한 방법이 있다.
profile
성장하는 개발자가 되고싶어요

0개의 댓글