개발 일기

[Building Microservices] CHAPTER 1 - 마이크로서비스란? 본문

도서/Building Microservices 마이크로서비스 아키텍처 구축

[Building Microservices] CHAPTER 1 - 마이크로서비스란?

개발 일기장 주인 2025. 4. 27. 02:18

최근 분산환경에 관심이 생겨 해당 도서를 학교 도서관에서 관련 도서를 빌렸고 필요한 부분을 골라 읽으면서 주요 내용을 정리해보고자 한다.

https://github.com/iamindian/References_Books/blob/master/Building%20Microservices%20Designing%20Fine-Grained%20Systems%202nd%20By%20Sam%20Newman.pdf

 

References_Books/Building Microservices Designing Fine-Grained Systems 2nd By Sam Newman.pdf at master · iamindian/References_B

My reference books. Contribute to iamindian/References_Books development by creating an account on GitHub.

github.com


 

1.1 마이크로서비스?

  • 마이크로서비스는 비즈니스 도메인에 따라 모델링된 독립적으로 릴리스 가능한 서비스로, 기능을 캡슐화하고 네트워크를 통해 다른 서비스들에 엑세스하게 해준다.
  • 서비스 지향 아키텍처의 한 종류지만, 서비스 경계를 정하는 방법과 독립적인 배포 가능성이 핵심이며 기술 중립적( 다양한 언어를 사용 가능하고 REST API, gRPC, 메시지 큐(Kafka, RabbitMQ)등 어떤 통신 방법도 가능)
  • 하나의 마이크로서비스는 `블랙박스`로 취급
    • 소비자(마이크로서비스 중 하나)는 가장 적절한 프로토콜을 사용해 1개 이상의 네트워크 엔드포인트(메시지/이벤트 큐 또는 REST API)를 통해 다른 마이크로서비스의 비즈니스 기능을 호스팅
    • 이때 데이터 저장 방식과 같은 상세 내부 구현 정보는 외부 세계에서는 완전 은폐되고 인터페이스를 제공
    • 즉, 공유 데이터베이스의 사용을 지양하고 각 마이크로서비스는 자체 데이터베이스를 캡슐화
  • 정보은닉이라는 개념을 수용
    • 가능한 한 많은 정보를 구성 요소에 감추고 외부 인터페이스를 통해 최소한의 정보만 노출
    • 캡슐화 == 정보 은닉이 아니라, 정보 은닉 기법중 하나가 캡슐화
    • 마이크로서비스 경계 내부의 변경은 업스트림 소비자에게 영향을 미치지 않으므로 독립적인 기능 릴리스 가능

1.2 마이크로서비스 핵심 개념

  1. 독립적 배포성
    • 다른 마이크로서비스를 배포하지 않고도 마이크로서비스를 변경, 배포, 릴리스 할 수 있음
    • 독립적 배포 위해 마이크로서비스 간 느슨한 결합 → 다른 서비스를 변경하지 않고도 한 서비스를 변경할 수 있어야 한다
  2. 비즈니스 도메인 중심의 모델링(도메인 주도 설계- Domain Driven Design)
    • 새로운 기능 추가를 조금 더 쉽게(확장성)
    • 마이크로서비스 간에 다양한 방식으로 재 결합하여 새로운 기능 제공
    • 이때 가능한 한 서비스 간 변경을 적게 수행할 수 있는 방법
  3. 자기 상태 소유
    • 한 마이크로서비스가 다른 마이크로서비스가 소유한 데이터에 엑세스하려면 두 번째 마이크로서비스에 데이터를 요청해야 한다.
    • 어떤 데이터를 공유하고 감출지 결정하는 능력을 제공하므로 자유롭게 변경할 수 있는 기능(내부 구현)과 거의 변경하지 않는 기능(소비자가 사용하는 외부 인터페이스)을 명확히 분리할 수 있게 해준다.
    • 독립적 배포성을 위해 하위 호환성이 없는 변경을 제한해야 하며 만약 업스트림 소비자와의 호환성을 깨뜨리면 소비자들에게도 변경을 강요하게 된다.
    • 내부 상태를 감추는 것 : OOP의 캡슐화와 유사 / 캡슐화는 정보 은닉의 방법 중 하나
  4. 크기
    • 하나의 마이크로서비스의 크기는 상황에 따라 좌우된다.
    • 첫째, 얼마나 많은 마이크로서비스를 처리할 수 있는가?
    • 둘째, 모든 것이 끔찍하게 결합돼 엉망인 상황을 피하면서 마이크로서비스 경계를 최대한 활용하려면 어떻게 경계를 정의해야하는가?
  5. 유연성
    • 마이크로서비스는 비용을 지불하고 유연성을 얻는다.
    • 다이얼을 돌리는 것과 같이 다이얼을 높은 쪽으로 돌리고 더 많은 마이크로서비스를 사용할수록 유연성은 높아지지만 그만큼 고충도 늘어난다.
    • 따라서 점진적 마이크로서비스 채택 지지
  6. 아키텍처와 조직의 정렬 
    • IT 조직에서 사람들을 그룹화하는 기본 방법은 핵심 역량 측면. 즉, Before : 기술 기능의 높은 응집력
    • 핸드오프와 사일로를 줄이기 위해 사람들을 다양한 기술을 갖춘 팀으로 묶음. After : 비즈니스 기능의 높은 응집력
      ※ 핸드오프 :
      한 작업이 끝나고 다른 사람(팀)에게 넘기는 과정
      ※ 사일로 :
      팀이나 부서가 서로 고립된 상태로 일하는 것
    • 시스템에서 요청받는 변경 요구 사항의 대부분은 비즈니스 기능의 변경과 관련 있을텐데 아래 Figure1-3과 같이 기술 기능 단위로 한 경우 비즈니스 기능이 3계층 모두에 분산돼 있어 이를 변경하기 위해서는 이 계층들을 넘어갈 가능성이 높다. 따라서 변경을 더 쉽게 만들고 싶다면 비즈니스 기능의 응집력을 선택하고 이를 묶어서 Figure1-4와 같이 팀을 구성해야 한다.
    • Figure1-5에서 고객 마이크로서비스는 3계층으로 된 얇은 슬라이스 부분(고객 관련)을 캡슐화 한다.

 

콘웨이의 법칙(Conway's law)
시스템을 설계하는 조직은 이러한 조직의 커뮤니케이션 구조를 본떠 설계하도록 제한된다.

1.3 모놀리스

해당 파트는 마이크로서비스 아키텍처 자체가 모놀리식 아키텍처의 대안으로 거론되는 것이기 때문에 모놀리스에 대해서도 알 필요가 있기에 존재하는 파트이다.

모놀리식과 마이크로서비스의 구분 짓는 요인은 바로 배포 단위이다. 시스템에서 모든 기능이 함께 배포돼야 한다면 이는 모놀리식.

 

필자는 '모놀리스'라는 용어를 '레거시'와 동일시해서는 안 된다고 말한다.
오히려 모놀리스 아키텍처가 프로젝트에 더 적합하다면, 주저 없이 이를 선택해야 한다.
반대로, 마이크로서비스 아키텍처는 명확하고 확실한 도입 이유가 있을 때에만 선택해야 한다고 강조한다.

 

▶ 단일 프로세스형 모놀리스

 

 

  • 우리가 흔히 아는 고전적 모놀리스.
  • Ruby on Rails의 창시자인 David Heinemeier Hansson(DHH)도
    이 방식이 소규모 조직에서는 매우 적합하다고 주장했다.
  • 그러나 조직이 성장하고, 코드베이스가 커지면서
    점차 모듈식 모놀리스로의 전환이 필요해진다.

 

 

 

 

 

 

 

 

 

 

 

 모듈식 모놀리스

  • 단일 프로세스형 모놀리스서브셋.
  • 단일 프로세스 안에서 모듈별로 분리된 구조를 가진다.
  • 각 모듈은 어느 정도 독립적으로 개발할 수 있으나,
    배포는 여전히 하나로 묶여야 한다.
  • 모듈 경계를 잘 정의하면 병렬 개발이 가능하다.

 

문제점

  • 대부분 데이터베이스가 통합되어 있어서
    모듈이 완전히 독립적이지 못하다.
  • 이를 해결하기 위해 모듈별로 데이터베이스를 분리하는 접근이 등장한다.
    • ex) 멀티 데이터소스(Multiple Datasource) 구성

 

 

 

▶ 분산형 모놀리스

  • 해당 부분은 책에서 긍정적인 설명이 아니라 부정적인 입장이다.
  • 정보 은닉과 비즈니스 기능의 응집력 같은 개념을 그다지 중시하지 않는 환경에서 나타나며 강하게 결합되어 변경 사항은 서비스 경계를 넘어 전파되고 변경 범위가 제한된 것처럼 보여도 시스템의 다른 부분까지 영향을 끼칠 수 있다고 한다.

    정리해보면...
  • 한 서비스만 고치려 해도 전체 서비스에 영향이 간다.
  • 하나의 작은 업데이트가 전체 시스템 장애를 일으킬 수 있다.
  • 시스템은 점점 손대기 힘들어진다.

→ 필자는 이러한 아키텍처를 업무 과정에서 접하고 MSA에 대한 관심에 상당 부분 영향을 끼쳤다고 한다.

 

모놀리스의 단점 : 전달 경합

프로젝트와 팀의 규모가 커짐에 따라 같은 장소에서 작업함에 따라 서로를 방해하게 되고 이 문제를 전달 경합이라고 부름(필자가 쓰는 용어인듯?)
  • 서로 다른 개발자가 동일한 코드를 변경
  • 서로 다른 팀이 서로 다른 시간에 라이브(또는 배포 지연) 원하며
  • 소유권에 혼선

모놀리식이라고 해서 이를 무조건 겪는 것도 아니고 마이크로서비스 아키텍처를 구축한다고 해도 무조건 안 겪는 것은 아니지만 MSA가 더 구체적인 경계를 제공하기에 이 문제를 줄이는데 훨씬 유리


1.5 마이크로서비스의 장점

정보 은닉도메인 지향 설계의 개념을 분산 시스템에 결합하여 큰 장점으로 이어진다.


기술 이질성

  • 각 마이크로서비스 별 서로 다른 기술 사용 가능
  • 데이터를 저장하는 방식으로 인해 시스템의 다른 부분을 변경 가능
    • SNS에서 소셜 그래프의 고도 상호 연결성을 반영하기 위해 그래프 지향 데이터베이스에서 사용자의 상호작용을 저장
    • 게시물에 대해서는 문서 지향적 저장소 등을 활용

견고성 : 벌크 헤드 - BulkHead (장애 전파 최소화)

  • 시스템 안의 한 컴포넌트(서비스)가 실패해도, 그 실패가 전체 시스템으로 퍼지지 않게 격리하는 것.
  • 서비스 경계는 명백한 벌크헤드(격벽)가 된다.
  • 모놀리식에서는 하나의 서비스가 실패하면 모든 것이 멈춘다. 이때 여러 머신에서 실행시켜서 대처할 수 있지만, 마이크로서비스의 경우 일부 구성 서비스가 완전히 죽더라도, 전체 시스템은 부분적으로 기능 저하를 시키면서 타 서비스는 계속 지속될 수 있도록 한다.


 확장성

  • 대규모 모놀리식 서비스에서는 전체 시스템의 작은 한 부분에 성능 제약이 있어도 거대한 시스템 전체 모든 것을 한 덩어리로 함께 확장해야한다. 이로 인해 필요 없는 부분도 함께 확장하게되고 쓸데없는 낭비되는 리소스가 발생한다.
  • 시스템이 여러 개의 작은 서비스로 쪼개져 있어 문제 되는 서비스만 골라서 확장(Scale-Out) 가능하다.


 배포 용이성

  • 모놀리식: 큰 애플리케이션에서 작은 변경을 적용하려면 전체 애플리케이션을 다시 배포해야 하므로 위험하다. 따라서 배포 시 여러 변경사항들을 누적시킨 후 실행하게되고, 그로 인해 배포 시 큰 변화가 일어나게 된다.
  • 마이크로서비스: 각각의 서비스가 독립적으로 배포 가능하여 코드 변경 후 빠르게 배포할 수 있고, 문제가 생기면 문제를 특정 서비스로 격리하여 쉽게 롤백할 수 있다. 이로 인해 새로운 기능을 빠르게 고객에게 제공할 수 있다.


조직적 정렬

  • 모놀리식: 하나의 대규모 팀이 하나의 큰 코드베이스에서 작업하는 것이 비효율적이고, 특히 팀이 분산되어 있으면 더 복잡해진다.
  • 마이크로서비스: 각 서비스는 작은 팀들이 담당하게 되어, 팀 크기와 생산성을 최적화할 수 있다. 또한 조직의 변화에 따라 서비스의 소유권을 쉽게 변경할 수 있어, 아키텍처와 조직 간의 정렬을 유지할 수 있다.

1.6 마이크로서비스의 단점

  1. 개발자 경험 (Developer Experience)
    서비스가 많아질수록 개발자 경험이 어려워질 수 있습니다. JVM과 같은 더 많은 리소스를 사용하는 런타임에서는 한 대의 개발 머신에서 실행할 수 있는 Microservice 수가 제한됩니다. 예를 들어, JVM 기반 Microservice는 4~5개 정도는 실행할 수 있지만, 10개나 20개는 어려울 수 있습니다. 개발자가 전체 시스템을 로컬에서 실행할 수 없는 경우에 대해서 어떻게 처리할지에 대한 고민이 필요합니다.

  2. 기술 과부하 (Technology Overload)
    Microservice 아키텍처를 채택하기 위한 새로운 기술들이 많습니다. 많은 기술들이 "Microservice 친화적"이라고 재브랜딩된 경우도 있지만, 일부 기술은 실제로 이 아키텍처의 복잡성을 해결하는 데 도움을 줍니다. 그러나 새로운 기술이 너무 많아지면 "기술에 대한 집착"으로 이어질 수 있고, 이는 프로젝트의 복잡도를 더할 수 있습니다. 새로운 기술을 도입할 때는 필요에 맞춰 점진적으로 도입하는 것이 중요합니다.

  3. 비용 (Cost)
    Microservice 아키텍처를 도입하면 여러 가지 측면에서 비용이 증가할 수 있습니다. 예를 들어, 더 많은 프로세스, 서버, 네트워크 및 저장소를 운영해야 하며, 추가적인 라이센스 비용이 발생할 수 있습니다. 또한, 팀이나 조직에 변화를 도입하는 데 시간이 걸리므로 기능을 출시하는 속도가 늦어질 수 있습니다. 비용 절감을 목표로 하는 조직에겐 Microservices가 적합하지 않을 수 있습니다.

  4. 보고 (Reporting)
    Monolithic 시스템에서는 데이터가 하나의 데이터베이스에 모여 있어 쉽게 보고서를 작성할 수 있습니다. 그러나 Microservice 아키텍처에서는 데이터가 여러 데이터베이스에 분산되기 때문에, 이를 통합하여 보고서를 생성하는 것이 어려워질 수 있습니다. 실시간 보고를 위해 스트리밍 기술을 사용할 수도 있지만, 이는 새로운 기술의 도입을 필요로 할 수 있습니다.

  5. 모니터링과 문제 해결 (Monitoring and Troubleshooting)
    Monolithic 시스템에서는 모니터링이 상대적으로 간단합니다. 그러나 Microservice 아키텍처에서는 수십 개 또는 수백 개의 프로세스를 관리해야 하기 때문에, 하나의 프로세스에서 문제가 발생했을 때 이를 모니터링하고 적절히 대응하는 것이 어려울 수 있습니다. 또한, CPU 사용량이 100%인 프로세스가 하나일 경우, 이를 어떻게 처리할 것인지에 대한 고민이 필요합니다.

  6. 보안 (Security)
    단일 프로세스의 모놀리식 시스템에서는 많은 정보가 하나의 프로세스 내에서 흐르지만, Microservice 아키텍처에서는 서비스 간에 데이터를 주고받게 됩니다. 이로 인해 네트워크를 통한 데이터 전송 시 보안 취약점이 발생할 수 있으며, 데이터 전송 보호와 서비스 엔드포인트 보호에 더 많은 신경을 써야 합니다.

  7. 테스트 (Testing)
    Microservice 아키텍처에서의 자동화된 기능 테스트는 더 어려울 수 있습니다. 테스트의 범위가 넓어질수록 테스트 설정이 복잡해지고, 실행 시간이 길어지며, 실패 시 문제를 파악하기가 어려워질 수 있습니다. 시스템이 커질수록 끝에서 끝까지의 테스트가 비효율적일 수 있으며, 대신 계약 기반 테스트나 생산 환경에서의 테스트 등을 사용해야 할 수 있습니다.

  8. 지연 시간 (Latency)
    Microservice 아키텍처에서는 데이터를 처리하는 과정이 여러 서비스로 분산될 수 있기 때문에, 이전보다 더 많은 네트워크 호출이 필요하게 됩니다. 이는 시스템의 지연 시간을 증가시킬 수 있습니다. 따라서, 지연 시간을 측정하고 이를 최적화하는 작업이 중요합니다.

  9. 데이터 일관성 (Data Consistency)
    Monolithic 시스템에서는 데이터가 하나의 데이터베이스에 있기 때문에 트랜잭션을 쉽게 관리할 수 있습니다. 그러나 Microservice 아키텍처에서는 데이터가 여러 서비스에 분산되어 있기 때문에, 분산 시스템에서 데이터 일관성을 유지하는 것이 어려울 수 있습니다. 이 문제를 해결하기 위해서는 'Saga'나 'Eventual Consistency'와 같은 패턴을 적용해야 할 수 있습니다.