/ TECH

[마이크로서비스] 스프링 마이크로서비스 요약 정리 (spring microservice, msa)

스프링마이크로서비스의 책내용중 마이크로서비스를 개발함에 있어 가장 중요한 개념과 원칙들 설계방법 부분을 예제 와 함께 정리

[마이크로서비스] 스프링 마이크로서비스 정리

스프링 마이크로서비스 책 내용을 모두 요약 한 것이 아니라 개인 적으로 중요하다고 생각되는 개념만 정리 한 것임을 미리 밝혀 둡니다.

마이크로서비스의 원칙

마이크로서비스를 설계하는 원칙들은 좋은 마이크로서비스를 설계하고 구현하는데 필수적 이다.

서비스하나에 책임도 하나

객체지향에 등장하는 개념인 SOLID 원칙중 하나인 단일책임원칙과 마찬가지로 하나의 마이크로서비스는 하나의 책임을 가져야한다. 그렇게 됨으로써 각 서비스간 낮은 결합도를 유지 할 수 있다.

하나의 책임이라는 의미가 중요한 듯 하다 하나의 기능이 아니라 하나의 책임 즉 배달과 주문이 있다고 한다면 배달은 배달과 관련된 기능만 수행한다. 배달 마이크로 서비스가 주문의 상태를 변경하거나 하는 기능이 포함되면 안된다는 의미다.

이 것은 객제관점에서 보아도 배달객체가 주문객제를 직접 변경하는 것 매우 부자연스럽다. 객체 관점에서도 필요할 때는 주문 객체에서 제공되는 주문상태 변경 메소드를 호출하여 주문객체에게 주문상태 변경해달라고 요청하는 모습처럼 마이크로 서비스도 하나의 객체단위로 보는 관점이 필요 하다고 본다.

spring-microservice-diagrams-monolithic-to-microservice

마이크로서비스는 자율적

책 내용은 구구절절한데 한마디로 하나의 단독 서비스 처럼 돌아갸야 된다는 이야기다. 웹서비스라면 하나의 웹서비스가 독립적으로 구동되는 형태로 생각하면 이해가 빠를 듯 하다.

마이크로서비스의 경계 설정

마이크로 서비스의 경계 설정에 있어 만병 통치약은 없다

마이크로서비스의 경계 설정 시 피해야 할 조건

마이크로서비스간 낮은 응집도와 결합도를 유지 해야한다

  • 너무 많은 정보교환
  • 너무 많은 동기적 요청, 응답
  • 순환 의존 관계
  • 트랜잭션 범위가 여러 마이크로서비스에 걸치지 않게 해야함

적절한 마이크로서비스 경계 설정 조건

자율적인 기능

  • 외부 기능에 대한 의존도가 낮다

배포 단위의 크기

  • 기능이 많은 서비스는 배포규모가 커진다
  • 배포단위의 크기를 감당 가능한 수준으로 유지

분리하기 적합한 기능 또는 서브도메인

  • 마이크로서비스 전환시 자원소모량, 소유 비용, 비즈니스 유용성, 유연성 등이 분석 기준이 된다
  • 마이크로서비스로의 분리가 유용한 선택인지, 분석기준을 통하여 판단한다
  • 검색 요청이 전체 리소스에 많은 부분을 차지하는 시스템이라면 분리 시 여러가지로 유리 하다

하나의 제품으로 생각을 해본다

  • 경계 지어진 마이크로서비스가 하나의 제품으로 구성될 수 있는지의 관점에서 평가 해보자

동기와 비동기 선택기준

어느 하나의 방식만으로 시스템을 개발하는 것은 불가능, 장단점을 따져서 두방식을 적절히 조합 해야한다

동기

  • 사용자가 즉시 응답을 받아야 하는 서비스
  • 마이크로서비스간 의존성을 높이는 단점

비동기

  • 즉시 응답 받지 않아도 되는 서비스
    예) 이메일, 문자 발송, 포인트 서비스, 재고 갱신

마이크로 서비스의 과제

마이크로 서비스와 대규모 데이터

주문 마이크로 서비스와 고객 마이크로서비스가 있다고 할 경우 고객별 주문 리스트를 가져와야할 경우에 대한 문제와 고려해 볼 방법들 결론 적으로 주문 - 고객을 조인쿼리로 가져올 수 없다는 문제에 대한 해결 방법

필요한 데이터를 미리 생성

  • 즉 고객 별 주문 리스트를 가져오고 싶으면 각각의 마이크로 서비스에서 가져와 필요한 곳에 데이터를 생성(복제본) 해놓는 방법
  • 단점은 데이터 중복문제

    이 방법 없이 조인쿼리를 사용할 수 없는 상황에서 두 마이크로 서비스의 데이터를 리스트로 가져오는 방법은 경험상 정말 비즈니스 로직이 복잡해진다.

    이런 페이지들이 많다면 개발리소스도 훨씬 많이 들어가고, 어떤 경우는 특정 검색조건에 따라 리스트를 가져올 수 없는 경우도 발생한다.

    내 경험상 데이터 중복 문제가 단점이라고 이 방법 없이 여러 마이크로 서비스의 데이터를 조인 없이 조인과 같은 결과를 내는 방법으로 개발을 하는 것은 정말 실수 하는 것이라고 조심스럽게 말해본다.

  • 복제본 데이터를 어떻게 구성할 것인가는 마이크로서비스를 어떻게 구성 했느냐에 따라 달라지므로 상황에 맞게 구성
    • 통합적인 통계 관련 데이터를 제공 하는 서비스가 있다고 한다면 각 마이크로 서비스로 부터 지속적으로 데이터의 생성 변화를 입수하여 데이터 웨어하우스 같은 형태로 관리한다.
    • 입수 방식은 이벤트 소싱(event pub/sub) 방식이 대표적, 메시지 큐 같은 여러 서비스를 활용, rabbitMQ, kafka 등등

의존 관계 관리

  • 서비스 경계를 적절하게 설정해서 의존성을 낮춘다.
  • 의존성을 가능한 느슨하게 설계해서 변경에 대한 영향을 낮춘다.
  • 비동기 통신 방식을 통해 서비스간 상호작용이 일어나도록 설계.
  • 서킷 브레이커 같은 패턴을 사용하여 의존성 문제의 전파를 차단.
  • 의존 관계 그래프 같은 시각화를 통하여 의존 관계를 모니터링.

사실 위 조건들이 마이크로 서비스 설계시 가장 어려운 문제 인 듯 하다.
모놀리식 서비스 와 마이크로 서비스 동기와 비동기 등이 어느 한쪽을 선택하면 이익을 얻는 대신 반드시 손해를 보게되는 trade-off 관계 이기 때문이다.

마이크로서비스로의 전환 계획

실제 책에서 예제로 나오는 항공사 예약 시스템 대신 본인이 주로 다뤄 왔단 배달 도메인을 예로 설명 합니다.

전환 관점에서 제기되는 몇가지 중요한 질문

  • 마이크로서비스 경계 식별
  • 마이그레이션을 위한 마이크로서비스 우선순위 지정
  • 전화 단계에서의 데이터 동기화 처리
  • 이전 UI와 새로운 UI를 다루기 위한 사용자 인터페이스 통합
  • 새로운 시스템에서의 참조 데이터 처리
  • 비즈니스 범위기 제대로 유지될 수 있게 보장하는 테스트 전략
  • 마이크로 서비스의 기능. 프레임워크 등과 같은 마이크로서비스 개발을 위한 전제 조건 확인

첫번째 - 마이크로서비스의 경계 식별

  • 가장 먼저 해야 할 일은 모놀리식 서비스에서 마이크로서비스로 전환 하고자 하는 도메인의 경계를 식별하는 것
  • 모놀리식 서비스를 분해 해본다는 관점으로 접근

두번째 - 의존 관계 분석

  • 첫번째 단계에서 뽑아낸 마이크로서비스 후보들 간의 의존성을 분석한다.
  • 분석한 의존성을 바탕으로 의존 관계 그래프를 그려본다.

dependency-diagram

세번째 - 면밀한 의존 관계 분석

이벤트 소싱에 유리한 케이스

spring-microservice-get-delivery-list

  • 배달 운영에 관한 각종 현황 정보 조회 및 모니터링 가능한 배달운영관리 시스템과 배달을 분리 할 수 있다.
  • 위 그림 처림 배달 운영 시스템이 배달을 직접 가져오는 대신 배달의 생성 및 상태 변경을 배달 모듈이 이벤트를 발행하고, 배달운영관리 시스템은 배달의 변경사항을 구독한다.
  • 이런 시나리오는 배달, 라이더, 배달팁 모듈들에서 변경사항 이벤트를 발행하고, 배달 운영 관리 시스템음 각 모듈의 변경사항을 구독하여 관리하는 방식으로 여러 모듈들에게 적용할 수 있다.

이벤트 소싱에 불리한 케이스(1)

spring-microservice-get-delivery-list-from-calculator

  • 라이더에게 지급할 배달팁 정산을 위해서 정산 시스템 배달 목록을 가져오는데 월단위, 주단위, 일단위 정산이 일반적이므로 모든 배달 데이터는 사실상 필요가 없다
  • 이벤트 소싱으로 구성 된다면 정산 시스템은 항상 모든 배달건의 상태 변경에 대한 이벤트를 구독 받아 처리 해야하므로 불필요한 자원 낭비가 될 수 있다.
  • 차라리 정산 주기에 따라 1번씩 해당 하는 정산 기간의 배달 데이터를 공급 배달 모듈로 부터 공급 받는 것이 결과적으로 유리하다.

이벤트 소싱에 불리한 케이스(2)

spring-microservice-get-delivery-list-from-crm

  • 고객응대 시스템에서 발생하는 배달건의 고객응대 건수는 발생하는 배달 건수에 비해 현저하게 적은 건수를 가진다. (배달이 100건이라고 한다면 배달불만 접수는 10건이라고 한다면)
  • 이런 경우 고객응대 시스템에서 배달건마다 발생하는 모든 이벤트를 구독받아 배달 데이터를 유지하고 있는 것은 사실상 리소스 낭비에 해당한다.
  • 배달건에 대한 고객 불만 사항이 발생 할때 차라리 직접 배달을 가져오는 편이 유리하다.

동기화 되어야 할 서비스들 사이에서의 이벤트소싱

spring-microservice-delivery-dashboard-direct

  • 배달 현황 및 각종 정보를 관리하고 실시간 모니터링하는 서비스가 있다고 한다면 지속적으로 각각의 마이크로서비스로 분리된 시스템에서(배달, 라이더, 배달로) 주기적으로 데이터를 직접 가져오는 방식이 될 것이다.
  • 위 그림과 같은 직접 적인 방식에서 아래 그림과 같은 이벤트 소싱 방식으로 전환 할 수 있다.

spring-microservice-delivery-dashboard-event-sourcing

  • 위 그림과 같은 이벤트 소싱 방식으로의 전환이 각 시스템간 의존성을 낮춘다.

동기화 되어야 할 서비스들 사이에서의 이벤트소싱 문제점

spring-microservice-wait-delivery-event-sourcing

  • 배달을 라이더에게 배차했을 경우 배차 대기 목록 서비스에서 배달상태변경 이벤트를 비동기 이벤트로 구독받아 변경사항을 반영하고 있다.
  • 라이더는 배차대기 목록을 보고 자신이 배달하고 싶은 배달건을 가져온다.
  • 이런 시나리오에서는 배차대기 배달목록이 비동기로 유지될 경우 배달 상태가 불일치하는 경우가 발생할 수 도 있다.
  • 이런경우 라이더는 이미 다른 라이더에게 배차가된 배달건을 가져올 수도 있다.

마이크로서비스간 유효성을 확인 해야하는 경우

spring-microservice-validate-delivery
배차의 경우 배달건을 배차 할 수 있는 배달건인지 유효성을 다음과 같이 확인 할 것이다.

  • 이 배달건은 미배차 배달 건인가?
  • 이 배달건은 금일 발생한 배달 건인가?
  • 이 배달건은 해당 배달권역의 배달건 인가?
  • 기타 등등

이런 경우는 아래 그림과 같이 복잡한 유효성을 확인 하는 것 보다 적적한 유효성을 기존으로 미 배차 배달건 목록을 배달 마이크로시스템에서 관리하여 타 시스템에게 제공하는 편이 유리할 것이다.
spring-microservice-management-wait-delivery-list

마이그레이션을 위한 마이크로서비스 우선순위 지정

타이틀이 애매한데 풀어서 이야기 하자면 모놀리식 시스템에서 마이크로서비스로 분리하여 전환하고자 초기 설계 이후 도출된 각 마이크로서비스들 중 어떤 서비스를 먼저 전환 해야하는지에 대한 이야기로 이해하면 될 듯 하다. 우선순위를 매기는 기준에 대한 설명.

의존관계

의존관계가 없거나 적은 서비스는 마이크로서비스로의 전환이 쉬운 반면, 의존관계가 매우 복잡하고 높은 서비스는 위험성과 전환 과정이 어렵다.

트랜잭션 크기(요청이 많고 적음)

트랜잭션의 크기가 큰 시스템을 마이크로서비스로 전환하는 것은 기존 레거시 시스템의 부하를 줄여주기 때문에 유지보수 관점에서 보았을 때 큰 가치가 있다. 그러나 위험부담이 크다는 단점도 있다.

어떤 위험부담이 있는지에 대한 내용이 책에 없다…..

리소스 이용율

서버자원을 많이 사용하는 서비스를 마이크로서비스로 전환하는 것은 기존 레거시시스템에 남아 있는 기능들이 더 잘 작동할 수 있다.

개념은 트랜잭션 크기 이야기와 일맥상통한다.

복잡도

덜 복잡한 시스템이 마이크로서비스로의 전환이 쉽다(당연한 이야기 아닌가??)

사업적 중요도

저자는 사업적 중요도가 높은 서비스를 마이크로서비스로의 전환하는 것이 좋다고하는데 이유설명이 없어서 아쉽다. 아마도 먼저언급한 여러가지 유용한 이점들이 사업적 중요도가 높은 서비스에게 적용되기 때문이라는 이유 일 듯 싶다.

변경속도

개발적인 변경이 빈번하게 이루어지는 서비스가 그렇지 않은 서비스보다 마이크로서비스로의 전환에 있어 우선순위가 높다.

역시나 책내용에 근거가 없다…

혁신

책 내용을 풀이하자면 서비스가 혁신적으로 변경되는 서비스들을 마이크로서비스로 전환하여 운영하는 것이 더 유리하다는 이야기다 서비스를 혁신적으로 변경해야할 때 기존 레거시 시스템에서 혁신적으로 변경하는 것이 더 어렵다고 이야기 하고 있다.

마이크로서비스로의 전환 중 레거시시스템과의 데이터 동기화

책 내용을 대략 풀이 하자면 전체 모놀리식 시스템을 한번에 모두 마이크로서비스로 전환하는 시나리오는 현실적으로 어렵기도 하고, 레거시 시스템에서 하나씩 분리하여 점진적으로 마이크로서비스로 전환하는 과정에서 레거시 시스템과 마이크로 시스템간의 데이터 동기화를 어떻게 할 것인가에 대한 이야기다.

예를 들어보자면

  • 배달과 라이더가 같은 시스템에 함께 존재 하였는데 라이더관리 시스템으로 분리
  • 분리된 라이더 관리 시스템에서는 라이더 정보를 등록,수정,삭제 관리한다.
  • 기존 레거시 시스템에서는 라이더정보 등록,수정,삭제는 제거 되고 라이더 관리 시스템에서 처리하고 있다.
  • 하지만 기존 레거시 시스템에서는 라이더와 배달건을 조회하는 목록 페이지가 여전히 존재한다.
  • 이 경우 여전히 레거시 시스템의 DB에서 라이더 정보를 가져오는 로직이 남아 있기 때문에 라이더 관리 시스템으로 이전 되기 전까지는 두 시스템 사이에 라이더 데이터는 동기화 되어야한다.

해결책

이벤트 소싱을 이용해서 해결, 즉 라이더 관리 시스템에서 라이더 정보의 생성, 수정, 삭제 이벤트를 발행하고 기존 레거시 시스템은 구독하여 로컬 DB에 반영하도록 한다.

[사족] 그런데 나중에 모두 라이더 관리 마이크로서비스로 전환 되더라도 대규모 데이터를 조인 없이 가져와야될 상황이라면 어짜피 이벤트소싱으로 구성해야되는 것은 마찬가지 이다.

참조 데이터 관리

책에서 이야기하는 참조 데이터가 어떤 데이터를 의미하는지 명확한 설명이 없어서 조금 애매한 부분이다. 마이크로서비스단위의 큰 도메인 데이터가 아니라(배달, 주문, 라이더 같은) 여러 마이크로서비스에서 필요에 의해 참조해야는 데이터 들이 아닌가 추측해본다.

예를 들자면 배달, 라이더 둘다 필요한 배달팁 정책 같은 데이터를 의미하는 것 일 수도 있다.

배달을 생성 할때 배달팁을 참조하여 배달가격을 책정하기에 필요하다. 이런 경우 마이크로서비스에서 기존레거시를 직접 호출하는 것은 기존 레거시 시스템에 트랜잭션이 몰릴수 있기 때문에 지양하라고 한다.

해결책

이벤트소싱 방식

참조 데이터를 처리하는 마이크로서비스를 따로 만들어 각 마이크로 서비스에 제공하는 방식을 추천하는데 이벤트소싱 방식은 동기화 문제가 있을 수 있다. 배달팁이 변경 되고 비동기 이벤트를 발행하고 배달 마이크로서비스에서 배달 생성시 아직 변경된 이벤트를 수신 받지 못한 상태에서 변경전 배달료로 배달이 생성될 수도 있다는 이야기다.

spring-microservice-diagrams-refer-data-event-sourcing

인메모리 데이터 그리드

참조 데이터 마이크로서비스는 참조데이터의 변경사항을 인메모리 데이터 그리드에 반영 처리하고 각 마이크로서비스들은 인메모리 데이터 그리드를 참조한다. 이 방법은 데이터 동기화에 대한 문제를 해결한다.

인메모리 데이터 그리드는 데이터를 메모리로 관리한다는 점에서 REDIS인가? 하고 생각 할 수 있지만 REDIS와는 또 다른 개념이 적용된 메모리 저장소 인 듯 하다. 자세한 개념은 구글링을 통해서 찾아보면 도움이 될 듯 하다.

spring-microservice-diagrams-refer-data-in-memory-data-grid

마무리

스프링 마이크로서비스의 책 내용중 마이크로서비스를 설계 하기 위해서 가장 중요한 원칙과 설계방법 장단점 등의 내용만 정리해 보았습니다.

kimchanjung

김찬정

좀 더 넓은 TEST 커버리지! 좀 더 나은 Architecture! 좀 더 나은 Code Pattern! 보다 더 간결하고 깔끔한 코드!를 항상 갈망 합니다.

Read More