Post

13장 마이크로서비스로 리팩터링

13장 마이크로서비스로 리팩터링

목차

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
13.1 마이크로서비스 리팩터링 개요
__13.1.1 모놀리스를 왜 리팩터링하는가?
__13.1.2 모놀리스 옥죄기
13.2 모놀리스 → 마이크로서비스 리팩터링 전략
__13.2.1 새 기능을 서비스로 구현한다
__13.2.2 표현 계층과 백엔드를 분리한다
__13.2.3 기능을 여러 서비스로 추출한다
13.3 서비스와 모놀리스 간 협동 설계
__13.3.1 통합 글루 설계
__13.3.2 서비스와 모놀리스에 걸쳐 데이터 일관성 유지
__13.3.3 인증/인가 처리
13.4 새 기능을 서비스로 구현: 배달 실패한 주문 처리
__13.4.1 배달 지연 서비스 설계
__13.4.2 배달 지연 서비스를 위한 통합 글루 설계
13.5 모놀리스 분해: 배달 관리 추출
__13.5.1 현행 배달 관리 기능
__13.5.2 배달 서비스 개요
__13.5.3 배달 서비스의 도메인 모델 설계
__13.5.4 배달 서비스의 통합 글루 설계
__13.5.5 배달 서비스와 상호 작용할 수 있게 모놀리스를 변경
13.6 마치며

정리 전략?

  • 전부 정리는 NO
  • 핵심중에서 꼭 적고 가야겠다 싶은 것만!
  • 나의 생각을 섞어서 적을것..!
  • 떠오르는 것 먼저 간단하게..!

내용

13.1 마이크로서비스 리팩터링 개요

__13.1.1 모놀리스를 왜 리팩터링하는가?

  • 유지 보수에 오래 걸리니까!, 테스트도 어렵고, 개발 공수도 많이 들고(msa에 비해서)

__13.1.2 모놀리스 옥죄기

  • 옥죄기를 하길 할건데 단계적으로 바꿔야한다!
  • 스트랭글러 애플리케이션 패턴. Strangler Application Pattern

값을 조기에 자주 검증

단계적 리팩터링은 투자에 따른 보상이 즉시적이다. 때문에 조금씩 리팩터링 하면서 새 기술스택 도입과 데브옵스 스타일로 개발/전달 하면 효과적이다.   애플리케이션에서 가장 가치가 큰 부분을 먼저 이전하면 더 효과적이다. 핵심 로직을 먼저 추출해 마이크로서비스로 리팩터링 하면, 해당 로직은 다른 서비스와 별개로 독립적으로 개발/수행 가능하며 그만큼 개발 속도는 더 빨리진다.  이런 과정에서 가치가 일찍 전달되면서 경영진에게도 어필이 가능하다.

모놀리스 변경사항을 최소화

모놀리스를 광범위하게 뜯어 고치는것은 시간도 많이 걸리고, 비싸고 위험하다.

기술 배포 인프라 : 모든것이 다 필요한 것은 아니다.

모든 인프라를 초기에 한꺼번에 투자 할 필요는 없다. 처음에는 테스트자동화 배포 파이프라인은 꼭 필요하다. 나머지는 이후 경험해보고 필요시 결정하라. 출처: https://freeend.tistory.com/117 [FreeEnd:티스토리]

13.2 모놀리스 → 마이크로서비스 리팩터링 전략

__13.2.1 새 기능을 서비스로 구현한다

  • 말 그대로

새 서비스를 모놀리스에 연계

새 서비스와 모놀리스를 통합하는 두개의 요소는 다음과 같다.

API게이트웨이 : 새 기능은 새 서비스로, 구 기능은 모놀리스로 라우팅 통합 글루 코드 : 새 서비스가 모놀리스 데이터 / 기능에 접근 할 수 있도록 통합글루를 구현한다.

통합 글루 코드는 스탠드어론 컴포너트가 아닌, IPC 를 이용한 서비스이다 출처: https://freeend.tistory.com/117 [FreeEnd:티스토리]

새기능을 서비스로 구현하는 시점

  • 핵심은 절대적인 것은 없다가 포인트.
  • 구현하기 어려운 케이스도 있긴 함.
    • 의미있는 서비스라고 하기에는 기능 자체가 너무 작은 경우
    • 새기능이 기존 모놀리스코드에 너무 단단히 매여있는 경우
    • 데이터 일관성을 보장 하기 힘든 경우

__13.2.2 표현 계층과 백엔드를 분리한다

  • 이렇게 함으로써 프론트 개발과 백엔드 개발을 나눌수 있고, 각자가 자신의 프로젝트를 빠르게 개발, 배포할 수 있다.

__13.2.3 기능을 여러 서비스로 추출한다

  • 모놀리스의 기능 1개를 여러 서비스로 추출한다는 의미.
  • API 끝점이 구현된 인바운드 어댑터
  • 도메인로직
  • DB접근 로직 등이 구현된 아웃바운드 어댑터
  • 모놀리스의 DB 스키마

도메인 모델 분리

  • 객체 레퍼런스를 솎아내기 위해 애그리거트 관점으로 생각할 필요가 있다. 레퍼런스를 기본키 필드로 대체 하자.
  • 서비스와 모놀리스 간에 데이터를 복제하면 변경 범위를 줄일 수 있다.

DB 리팩터링

  • 도메인 모델의 클래스는 대부분 영속적이라 필드가 DB스키마에 매핑되어있다. 따라서 서비스 DB로 옮길 필요가 있다.
  • 데이터를 복제해 DB클라이언트가 새 스키마를 사용하도록 단계적으로 업데이트하는 발상도 있다.

변경 범위를 줄이기 위해 데이터를 복제

  • 전이 기간 동안에는 원본 스키마를 유지하되, 원본 스키마와 신규 스키마를 동기화하는 트리거를 사용할 수 있다.

어떤 서비스를 언제 추출하나

  • 첫번째, 모놀리스의 개발을 동결하고, 요건이 있을 때마다 서비스를 추출하는 것이다. 모놀리스의 버그를 잡지 말고, 필요한 서비스를 추출해서 고쳐 개발하는것이다.
  • 두번째, 서비스 추출시 기대되는 혜특을 모듈별로 순위를 매기는 것이다. 다음은 추출하는것이 도 이로운 경우이다.
    • 개발가속화 : 개발 일정상, 개발 분량이 많을 것으로 예상 되는 파트를 서비스로 전환한다.
    • 성능, 확장성, 신뢰성 문제해결 : 성능, 확장성에 문제가 있거나 의심스러운 부분은 전환 할 만한 가치가 있다.
    • 다른 서비스로 추출할 수 있게 만듦 : 먼저 추출하면 디펜던시상 다른 서비스분리가 단순해지는 경우.
  • 이러한 리팩토링 테스크를 애플리케이션 백로그에 담아서 작업을 진행해보는 것은 어떠할까?

13.3 서비스와 모놀리스 간 협동 설계

__13.3.1 통합 글루 설계

통합 글루 설계

  • 통합 글루라고, 모놀리스와 msa를 연결해주는 다리에 대한 설계.
  • 서비스의 비즈니스 로직은 통합 글루가 어떤 IPC 로 데이터를 가지고 오는지 알 필요가 없으므로, IPC를 인터페이스로 캡슐화 하여 제공한다. 모놀리스의 비즈니스 로직은 통합글루가 어떻게 구현했든 알필요 없이 단순히 호출해 사용하면 된다.

상호 작용 스타일과 IPC 선택

  1. 조회API 를 이용하는 방식은 단순해 편리하지만 요청 개수가 많아지면 효율이 나빠진다. 그래서 일반적으로 API 는 잘 사용하지 않는다.
  2. 때문에 데이터 레플리카 (CQRS 뷰) 를 사용한다. 각 시스템의 이벤트를 구독해 각 데이터를 개별 DB에 관리해 조회를 하면 프로바이더를 반복해서 조회하는 쿼리 오버해드를 줄일 수 있다. 단, 모놀리스에 이벤트 발행 로직을 개발하는것은 쉽지 않다.  수정시에도 SAGA 나 이벤트를 사용해 양쪽 데이터베이스의 일관성을 유지한다.

부패-방지 계층 구현

  • 마이크로서비스를 완전히 새로 개발 할 경우, 전혀 다른 클래스명, 필드명, 필드값등을 가지게 될 것이다. 모놀리스와 서비스가 서로 소통하려면 DDD 에서 말하는 ACL(Anti-Corruption Layer, 부패-방지 계층)  을 구현 해야한다.
  • 부패-방지 계층은 상이한 두 도메인이 상대방을 더럽히지 않도록 변환해주는 소프트웨어 계층이다.
  • ACL 은 모놀리스의 도메인이 서비스 도메인을 더럽히지 못하게 하는데 목적이 있다. 때문에 ACL 을 구현한 클래스는 모놀리스의 언어와 서비스의 공용언어를 변환 해주어야 한다.
  • 모놀리스를 REST로 호출하는 서비스는 호출하는 요청값과 응답값을 ACL 로 변환 해줘야 하며, 모놀리스의 이벤트를 구독하는 서비스도 역시 ACL 로 적절히 언어를 변환 해야 한다.

모놀리스가 도메인 이벤트를 발행/구독하는 방법

  • 모놀리스가 이벤트를 발행하는 방법은 두가지이다.
    • 서비스가 사용하는것과 동일한 이벤트 발행 장치를 적용하는 방법엔티티를 변경하는 코드를 모두 찾아내어 이벤트 발행 API 를 삽입 하는 방식이다. 하지만 이렇게 모든 변경코드를 찾아내기는 쉽지 않고, Stored Procdure 로 구현된 로직은 이벤트 발행 자체가 불가능하다.
    • DB수준에서 이벤트를 발행 하는 방법트랜잭션 로그 테일링 (DB의 트랜잭션 로그를 분석해 데이터를 연동하는 방식. CDC 등) 이나 폴링을 사용한다. 이 방법은 간편하지만, DB수준에서만 이벤트를 발행할 뿐이고, 고수준의 비즈니스 이벤트는 발행 하기 어렵다.

__13.3.2 서비스와 모놀리스에 걸쳐 데이터 일관성 유지

  • 데이터 일관성을 위해서 통합 글루를 이용.
  • 참고로 각자의 영속성DB에 복제하는 방식으로 일관성을 유지한다.

보상 트랜잭션을 지원하도록 모놀리스를 고치기는 어렵다.

모놀리스에서 보상 트랜잭션 구현은 어렵다.

모놀리스에서 주방 서비스 추출한다고 했을 때 createOrder()을 구현한다고 해보자. 그럼 다음 단계로 구성된 단일 ACID 트랜잭션을 실행한다.

모놀리스

주문 내역 확인 주문 가능한 소비자인지 확인 소비자 신용카드 승인 주문 생성 사가

모놀리스: 주문을 APPROVAL_PENDING 상태로 생성, 주문 가능한 소비자인지 확인 주방 서비스: 주문 내역확인, 티켓을 CREATE_PENDING 상태로 생성 모놀리스: 신카 승인, 주문상태를 APPROVED 주방 서비스: 티켓 상태를 AWAITING_ACCEPTANCE -> 시맨틱 락으로 상태를 계속 두어야 한다. 하지만 기존 모놀리스에 상태를 추가하는 건 쉽지 않은 일 ..

사가 적용 시 모놀리스는 보상 트랜잭션을 지원할 필요가 없다.

  • 각 트랜잭션이 피봇/재시도 가능 트랜잭ㄱ션이라면 보상 트랜재겻ㄴ이 실행될 일이 없으므로 모놀리스 변경 작업을 최소화할 수 있다.

서비스 추출 순서를 조정하면 보상 트랜잭션을 모놀리스에 구현하지 않아도 된다.

__13.3.3 인증/인가 처리

  • 토큰이랑 세션 방식을 모두 고려한 인증 인가 처리가 필요하다 이런 내용이 였다.
  • 특히 msa는 세션으로 관리하지 않으니, 모놀리스에서 세션을 로그인 유지를 위해 쓰고 있다면, 그것을 쓰면서도 토큰의 동시 사용을 고려해야함.
  • 위 이미지 참고. api 게이트웨이는 userinfo쿠키를 검증 후 Authorization 요청 헤더에 넣어 서비스를 호출합니다. 서비스는 USERINFO 쿠키 검증 후 사용자 정보를 추출합니다.

13.4 새 기능을 서비스로 구현: 배달 실패한 주문 처리

  • 주문 상태를 추적해 약속한 시간에 음식을 배달할 수 없다면 알려야하는 코드를 작성해야 한다. 모놀리스 말고 새 기능을 서비스를 구현하는 방법 알아보자

__13.4.1 배달 지연 서비스 설계

  • 배달 지연 서비스는 Order, Restaurant 엔티티를 소유하고 있지 않음.

__13.4.2 배달 지연 서비스를 위한 통합 글루 설계

고객 연락처 데이터: 조회할 일 적고, 크기 작기에 모놀리스에서 api call 주문 상태, 음식점 데이터: 네트워크로 대량 데이터 전송은 비효율적이므로 레플리카

  1. 도메인 발행 : 고수준 도메인 이벤트 발행 가능.
  2. 트랜잭션 로그 테일링 -> DB 동기화이므로 1,2 뭐든 좋음

13.5 모놀리스 분해: 배달 관리 추출

__13.5.1 현행 배달 관리 기능

  • 첫번째 버전의 배달 서비스는 공개된 API는 표출하지 않고, 모놀리스에 의해서만 호출될 것임.
    • 안전한 방식의 분리.

__13.5.2 배달 서비스 개요

  • 질문을 하자!
    • 어떤 동작과 엔티티를 배달 서비스로 이전할까
    • 배달 서비스는 어떤 API를 표출하지?
    • 모놀리스는 어떤 API를 표출하지?

__13.5.3 배달 서비스의 도메인 모델 설계

  • 기존 코드 분석.
    • 어떤 엔티티랑 필드가 있지.
  • 이전할 데이터 결정
    • 모놀리가 API간 서로의 데이터에 어떻게 접근할까?
    • 동기화는 어떻게 하지?

__13.5.4 배달 서비스의 통합 글루 설계

  • 비동기 메시징 알림이나
  • Order도메인 이벤트를 배달 서비스가 구독
  • 구체적 서로가 서로에게 접근할 방법
    • 이벤트로 처리, api 로 처리.

__13.5.5 배달 서비스와 상호 작용할 수 있게 모놀리스를 변경

Delivery 인터페이스 정의

DeliveryService 인터페이스를 호출하도록 모놀리스를 리팩터링

DeliveryService 인터페이스 구현

  • 피처 토글을 사용하면 배달 서비스를 처음 오픈하더라도 훨씬 부담이 적음. 피처 토글이 기존 구현를 사용할지, 신규 구현체를 사용할 지 결정하게 둠.
  • 아하 모먼트!
    • 이거 모놀리스 -> 서비스 전환이 아니더라도 쓸만할듯.
    • 구현체버전을 토글식으로 만들어서 띄우거나 이설정을 때는 1버전, 이설정일때는 2버전 띄우도록 해서, 프론트 코드 수정없이 옛 구현코드로 금방돌릴수 있을듯.

13.6 마치며

  • 스트랭글러 애플리케이션 : 점진적 msa화
  • 새 기능을 서비스로 구현해서 현대 기술과 개발 프로세스를 쉽고 빠르게 적용해보자.
  • 모놀리스를 분해하는 주된 방법은 기능을 여러 서비스로 단계적으로 전환하는 것이다.
  • 통합글루를 이용, 모놀리스와 서비스간 협동이 가능하게 하자.
  • 도메일 모델사이를 변환하시키는 부패방지 계층을 도입하여 모놀리스 도메인 모델이 서비스 도메인 모델을 오염시키지 않게 하자.
  • DB에 서로 복제하는 방식.
  • 서비스 추출 순서를 잘 조정하면 굳이 모놀리스에 보상 트랜잭션을 구현할 필요가 없다.
  • 인-메모리 세션 기반의 보안 메커니즘과 서비스에서 쓰이는 토큰 기반의 보안 메커니즘을 동시 지원해야 합니다.

참고자료

https://freeend.tistory.com/117 https://velog.io/@jimin3263/msa-13.-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4%EB%A1%9C-%EB%A6%AC%ED%8C%A9%ED%84%B0%EB%A7%81-597y17vk

코드 예시

  • 없는 것으로 보임.
This post is licensed under CC BY 4.0 by the author.