Skip to main content Link Menu Expand (external link) Document Search Copy Copied

created at 2023-04-24

(서론) MSA Project 를 진행하면서 느낀 점

지금까지 유저서비스와 주문서비스들을 MSA 로 진행하면서 느낀 점인데, 기술에 계속 파묻히고 있는것 같습니다. 그래서 왜 MSA 로 변환하고 있는지 그 목적을 상기시키고 정리하고자 이 포스팅을 쓰게 되었습니다. 이 글을 다음에 대한 지식을 기본으로 기술됩니다.

Kafka 의 개념 및 구조, Saga 패턴, WebFlux, Netty, Spring-Cloud, Future.

1. MSA(Saga-choreography) 의 장점

MSA(Saga-choreography) 형태는 여러가지 장점을 가지고 있습니다. 크게 Event-Driven 의 장점, MSA 의 장점, Saga-choreography 에 따른 장점들을 모아놨다고 볼 수 있겠습니다.

  1. 뛰어난 확장성(Event) : 어떠한 서비스를 추가할 때, 이벤트 토픽만 구독하면 되죠!
  2. 이벤트 처리방식을 통한 진정한 non-blocking(Event) : 이벤트 처리방식을 사용하기때문에 가질 수 있는 이점이죠! 예로 클라이언트가 굳이 응답을 받지 않아도 되며, 서버가 오래 걸리는 기능을 수행할 때 이 이점이 극대화됩니다. 만약 이벤트 처리방식이 아닌 api call 방식을 사용한다면 성능이슈가 발생합니다. 아무리 async/non-blocking 을 해도 결국은 클라이언트가 결과를 반환받아야된다는 사실 때문이죠.

    하지만 클라이언트의 요청에 대한 즉답이 필요할 때는 이벤트의 non-blocking 이점은 사라집니다. 오직 확작성 이점만 남아있죠. 이벤트 방식 클라이언트 요청에 Server-Sent-Event 응답을 보내는 방법은 이전 포스팅에서 확인하실 수 있습니다.

  3. 뛰어난 확장성(MSA) : 모노 서비스를 각각 따로 떼서 여러개의 작은 서비스들로 서비스 매쉬를 구축한다면 유연한 확장성 이점을 가져올 수 있습니다. 만약 채팅 서비스가 서버자원이 더 필요할 때, 바로 수평확장 할 수 있죠(by Eureka 등록).
  4. 트랜젝션 보장(Saga) : 여기서 말하는 트랜젝션이란, 클라이언트의 요청과 1:1 대응되는 하나의 요청 시퀀스입니다. 이 트랜젝션을 Saga형태로 구성한다면, 요청을 통일된 시퀀스로 관리할 수 있습니다.
  5. 서비스 간 디커플링(MSA) : 서비스의 다운타임을 최소화 시킵니다. 현업과 대응하자면 팀을 구축하기 쉽고, 배포 의존도가 낮으며, 장애빈도 또한 낮출 수 있습니다.
  6. 서비스 간 디커플링(Saga-Choreography) : Orchestration 서비스에 대한 의존도가 없습니다. 따라서 좀 더 마이크로 서비스들이 개별로 동작하도록 도와줍니다. 전제는, 서비스의 이벤트 흐름을 미리 파악하고 있어야하죠!

2. MSA(Saga-choreography) 의 단점

그렇다면 단점이 무엇일까요? 제가 체감하고 있는 단점을 기술하겠습니다.

  1. 미칠듯한 복잡성 : Saga-choreography 패턴은 너무나도 복잡하고 까다롭습니다.
    1. 장점 4번의 트랜젝션 보장(Saga) 을 만족시키기 위해 별도의 eventId 를 관리하는 요청-트랜젝션 테이블을 추가적으로 만들고 관리해야 합니다.
    2. Kafka 토픽의 파티션 개수와 요청-트랜젝션 테이블의 lock 을 잘 관리해야합니다.

      Kafka 토픽의 파티션 별 스레드가 하나 할당되고, 이는 즉 두 개의 DB-트랜젝션이 동시에 수행될 수 있으며, 요청-트랜젝션 테이블의 row 에 lock 이 걸려야 한다는 것을 의미합니다. 그래서 보통 비관적 쓰기 잠금을 걸거나, 토픽에 key를 이용하여 하나의 요청은 일관된 파티션에만 삽입되도록 해야합니다. 꽤 까다롭죠?

    3. 요청-트랜젝션 테이블은 필수인데 이를 만약 RDB 로 설정한다면 성능이슈가 발생합니다. 애초에 RDB 는 insert/update 가 빠르지 않기 때문이죠.
    4. 이벤트 멱등성 처리를 해주어야 합니다. 동일 이벤트가 여러번 반복수행되지 않는 api 들은 eventId의 중복처리를 따로 해주어야하죠.
  2. 인증/인가의 복잡성 : 서비스를 전부 따로 떼놓으니 이제는 인증/인가가 까다로워집니다.
    1. Spring-cloud gateway 에 인증/인가를 설정해도 api-gateway를 거치지 않고 직접 서비스에 통신하게 될 수도 있죠. 그래서 API 명세를 정말 상세하게 작성해야 합니다.
    2. Session 을 사용한다면 수평확장된 서비스 내 sticky 한 세션을 만들어주어야 합니다.
  3. 수평확장된 서비스 간 RDB 동기화 : 만약 수평확장된 동일 서비스가 별도의 RDB를 따로 사용한다면 서로간의 동기화 과정이 필요합니다. 이를 Kafka-connector 로 동기화 할 순 있지만, 무한루프에 빠질 수 있기때문에 SMT(Single Message Transformation)로 잘 설정해주어야 합니다.

3. MSA + Kafka 에서 서비스 수평확장 시 고려점

img

4. 결론

저는 복잡해도 확장성/장애대응성 에 있어 MSA를 사용하고자 했음을 상기하였습니다.