MSA 개념 정리

오의석·2025년 1월 13일
1

중요 패턴 정리

라우팅 패턴

  • 요청을 특성 시스템 or 서비스로 올바르게 전달하는 방법에 대한 패턴.
  • API Gateway에서 라우팅 패턴 사용함

클라이언트 회복성 패턴

  • 클라이언트가 원격 서비스의 실패나 성능 저하에 대해 복구할 수 있도록 도와 주는 패턴
  • (내부 패턴) 서킷 브레이커 패턴 : 서비스 실패 or 성능 저하 -> 대체 로직 사용 or 호출 차단
  • (내부 패턴) 벌크헤드 패턴 : 원격 자원 호출은 독립된 스레드 풀로 분리 자원별로 스레드 풀 격리
    • 단일 장애 지점(Single Point of Failure, SPOF)을 방지
      • 단일 장애 지점 : 시스템의 구성 요소 중 하나가 고장나면 전체 시스템이 중단되는 지점
  • hystrix or resilience4j 라이브러리를 이용하여 해당 패턴 구현 가능

빌드 배포 패턴

  • CI/CD 패턴이 대표적. 코드 변경이 발생할 때마다 자동으로 빌드를 하고 배포하여 개발 주기를 단축.

로깅 패턴

  • 중앙 집중식 로깅 시스템(ELK)을 사용하면 여러 서버에서 발생하는 로그를 한 곳에 모을 수 있음.

보안 패턴

  • 인증과 권한 부여 패턴을 통해 사용자 및 시스템 접근 제어.
  • OAutho, JWT 인증 방식을 사용하여 보안 강화 및 서비스 간 안전한 통신 보장

기본 구조

Spring Cloud Config

  • 마이크로서비스 환경에서 애플리케이션 설정 정보를 중앙 집중화하여 관리하는 시스템
  • 분산된 환경의 서버에서 환경 설정 정보를 중앙에서 모아 관리를 하는데 도움을 주는 라이브러리
  • yml을 모아둔 github repository에서 설정파일들을 관리함.
    • 모아둔 yml파일에서는 당연히 암호화 관리 한다({chiper}사용)
    • private repo로 만들어야하며, 모아둔 yml repo 접근은 ssh와 같은 방식을 이용하여 접근한다.
  • Spring Cloud Config Client는 위의 서버에 주소와 파일명을 yml에 작성하여 연동

Spring Cloud Stream

  • 이벤트 중심 마이크로 서비스를 구축하기 위한 프레임워크
  • 외부 미들웨어와의 통신을 하기 위해서 통합 컴포넌트를 제공
  • 그러기 때문에 binder, binding 이라는 개념 존재
    • Spring Cloud 프로젝트에서 제공해주는 프레임워크 중 하나
    • Apache Kafka 또는 RabbitMQ 등을 사용하여 Spring Boot 어플리케이션과 메세지를 보내고 받음
    • (번외) 대용량 처리를 위해 설계된 kafka를 왜 사용하는가?
      • kafka streams API를 제공하여서.
        • 해당 라이브러리는 연속적인 이벤트 스트림 데이터를 좀 더 빠르고 간단하게 처리하여 연속적인 결과값 얻을 수 있기 때문
        • 정적인 데이터를 특정시간에 일괄로 처리하는 배치 프로세싱보다 연속적임

Spring Cloud Service Discovery

  • 서비스 인스턴스들을 서로 동적으로 발견하고, 네트워크 위치(IP, 포트)를 추상화하는 기능
  • 클라우드 환경에서 인스턴스는 AutoScaling, 생성, 삭제, 확장 등을 거치면서 IP나 Port들이 동적으로 변경될 가능성이 있어 필요(매번 수동 변경은 불편)
  • Eureka는 넷플릭스에서 개발한 서비스 디스커버리 시스템으로 가장 대표적
    • 서비스 인스턴스들을 등록하고, 다른 서비스에서 해당 인스턴스를 찾아 요청 가능
  • 서버 사이드 디스커버리와 클라이언트 사이드 디스커버리 방식 존재
    • 클라이언트 사이드 디스커버리 : Service Registry를 통해 서비스 호출
    • 서버 사이드 디스커버리 : Service Registry가 아닌 앞단의 Load Balancer를 통해 다른 서비스 호출
      (로드 밸런서가 내부의 Service Registry에게 질의함으로써 결과를 반환)
    • 차이 : MSA의 다른 서비스를 호출할 때 Service Registry를 통해서 다른 서비스를 호출하는가?
      • Spring Cloud Netflix Eureka : Service Registry의 서버 역할, 서비스들을 등록하는 역할
        • Eureka Server와 Eureka Client의 eureka.client.serviceUrl.defaultZone을 동일하게 구성하여 유레카 서버가 클라이언트들을 인식하여 알 수 있게됨
        • Eureka Client는 MSA의 각 서비스들에는 모두 Eureka Clients를 추가하면 된다.

API Gateway

  • 외부의 요청을 받아서 알맞는 도메인 Application에게 요청을 보내는 MSA 구성 요소
  • 클라이언트와 백엔드 서비스 간의 모든 요청을 라우팅하는 단일 진입점 역할
  • 인증, 권한 부여, 로깅, 트래픽 관리 등 여러 기능을 제공
  • 대표 라이브러리
    • Netflix Zuul : Servlet 기반 동기방식 [개발 및 유지보수 중지 상태]
    • Spring Cloud Gateway : Netty 기반 비동기방식(Non-Blocking), Spring webFlux 위에서 동작
      - 구성요소

      Route : 클라이언트 요청 -> 특정 서비스로 전달하는 규칙 (고유 ID + 목적지 URI + Predicate + Filter로 구성)
      Predicate : 라우팅 조건 정의 (시간, URI, 요청, 네트워크로 구성)
      Filter : 요청 및 응답을 수정하거나 추가 작업을 수행하는 기능

         

Spring Cloud Gateway vs Kong, NGINX

통합성 : Spring Cloud Gateway는 Spring 생태계와의 통합성이 뛰어나지만, Kong이나 NGINX는 독립적인 API 게이트웨이 솔루션으로 더 다양한 언어와 프레임워크와의 호환성을 가진다.
확장성 : Kong과 NGINX는 고성능의 트래픽 처리를 위해 최적화되어 있으며, 대규모 분산 환경에서 유리할 수 있다.

출처


MSA 간의 서비스 연결

  • 기능별로 서비스를 나눈다.
  • 동기적 호출 시에는 OpenFeign을 쓴다.
    • 인터페이스에 @FeignClient(name = "Feign Client 이름(member)", path = "호출할 API url (/api/member)")
  • 비동기적인 메시지 브로커 방식을 많이 쓰임 (Kafka, RabbitMQ 등)
  • 같이보면 좋은 사이트
    링크1, 링크2, 링크3

MSA 서비스 장애 대응 (클라이언트 회복성 패턴 관련)

  • 장애 대응 예시 : 요청 실패시, 요청의 Timeout 시간만큼 요청 스레드를 점유 / 응답 지연시, Latency 시간만큼 요청 스레드를 점유
    • 서버의 스레드풀이 고갈되어 전체 서비스의 장애로 이어짐 / 사용자는 오랜 시간 지연 후 에러 발생
  • 라이브러리
    • Netflix Hystrix - 더 이상 개발 되지 않고 있음
    • Resilience4J - 추천
  • 각 서비스에서 적용하고 싶은 서비스에만 설정하면 된다.
  • 방식 (동기적으로 구성할 경우)
    • 회로 차단기 패턴 : 요청 시간 및 실패 횟수에 따라 Closed or Open 상태 전환 (시간 및 호출은 야믈에서 세팅)
          @FeignClient(name = "Feign Client 이름(member)", path = "호출할 API url (/api/member)")
          @CircuitBreaker(name = "circuit")
  • 폴백 패턴 : Circuit Breaker가 Open 상태인 상황에서 사용자 요청을 에러로 응답하지 않고 성공(미리 설정한 응답)으로 응답
          @FeignClient(name = "Feign Client 이름(member)", path = "호출할 API url (/api/member)", fallback = CustomFallback.class)
          @CircuitBreaker(name = "circuit")
  • 벌크헤드 패턴 : 동시 호출 요청 수 제한, 스레드폴 설정 가능
          @FeignClient(name = "Feign Client 이름(member)", path = "호출할 API url (/api/member)", fallback = CustomFallback.class)
          @CircuitBreaker(name = "circuit")
          public class ClassName {
            @GetMapping
            @Bulkhead(name = "야믈에 설정한 인스턴스명", fallbackMethod = "bulkheadFallbackMethod")
            publice Response functionName(String variableName);
            publice Response bulkheadFallbackMethod(Throwable e);
          }

출처


MSA 트랜잭션 처리

  • 서비스 분리로 트랜잭션의 특성 중 하나인 원자성을 보장하기 어려워짐
  • 방법
    • 2PC 패턴(Two-Phase Commit)
            1단계: 모든 참여자가 트랜잭션을 커밋할 준비가 되었는지 확인하는 prepare 단계.
            2단계: 각 참여자가 준비가 되면 commit하거나 실패할 경우 abort하는 단계.
      • A, B, C 서비스에서 트랜잭션을 처리하는 경우, 모두 커밋 준비가 되면 트랜잭션을 완료하고, 하나라도 실패하면 모두 취소됩니다.
      • 단점 :
    • Saga 패턴 : 긴 트랜잭션을 여러 개의 짧은 로컬 트랜잭션으로 분리하여 처리
      • 예약 시스템에서 A, B, C 서비스가 각각 로컬 트랜잭션을 처리하고, 실패 시 각각 보상 트랜잭션을 실행하여 데이터를 일관성 있게 유지합니다.
        • 보상 트랜잭션 : 물리적 개념이 아니라 롤백된 것처럼 비즈니스적으로 롤백 처리하는 것 ( ex : Status 컬럼 상태 success -> cancled)
      • Choreographed Saga : 이벤트 및 보상 트랜잭션 처리 주체가 각 마이크로 서비스
        • A 서비스의 A 트랜잭션 처리 -> 메세지큐로 B 서비스로 전달 -> B 서비스 트랜잭션 처리 -> 결과(Success/Fail)이벤트를 메세지큐 전달(성공이벤트는 선택)
          • 실패 이벤트는 A 서비스로 전달 -> A 서비스에서 보상 트랜잭션 발생
      • Orchestrated Saga : 이벤트 및 보상 트랜잭션 처리의 주체로 'Orchestrator'가 존재하여 중앙에서 처리
        • 서비스간 결합도 감소(because 각 마이크로 서비스가 다른 마이크로서비스를 알 필요 없기 때문)
        • 주의 : Orchestrator가 전체 Flow를 관리. so, 단일 장애 지점(SPOF)가 되어 장애 발생 시 모든 서비스 장애 전파 가능
profile
끊임없이 나아가는 사람이 되어볼게요.

1개의 댓글

comment-user-thumbnail
2025년 1월 13일

정말 유익하네요!

답글 달기