MSA-9. MSA 적용과 API Gateway

드디어 MSA를 구현하기 위해 모놀리식으로 작성하던 프로젝트를 나누는 작업을 시작했다. 우선 도메인별로 기능을 묶을라 했는데 코드가 하도 꼬여 있어서 그냥 프로젝트를 새로 파기로 결심했다. 기존 모놀리식 프로젝트 안녕… 새로 [member / product / order / API gateway] eureka client / eureka server 이렇게 나누고, db를 세 개의 마이크로 서비스에 따라 각자 파기로 했다. 레디스는 별다른 분리 없이 하나의 레디스를 사용한다.

MSA 적용하기

1. 도메인 분리하여 마이크로 서비스 생성

  • Eureka Server
  • Eureka Client
    • API-gateway - 8080
    • member - 8081
      • redis: 6379:6379
      • mysql: 3306:3306
        • db: spring_proj_member
    • product - 8082
      • redis: 6380:6379
      • mysql: 3308:3306
        • db: spring_proj_product
    • order - 8083
      • redis: 6381:6379
      • mysql: 3309:3306
        • db: spring_proj_order
    • payment - 8084
      • redis: 6382:6379

이런 식으로 연결했다. 호스트 포트는 충돌이 일어나니 다른 포트로 연결하고, 컨테이너를 각각 세웠다.

세 가지의 도메인 각각 db, 인텔리제이 프로젝트를 생성하고 도커 설정까지 완료했다. 위에서 명시해 둔 것처럼 각 프로젝트는 로컬 포트 8081, 8082, 8083로 설정했고 동시에 구동되는 것까지 확인.

  • 약간 이렇게 생각하면 쉽겠다. API gateway는 무조건 인증이 완료된 요청만 각각의 마이크로 서비스에 전달한다…!
  • 그럼 우선 인증 관련 내용은 전부 제거하고 API gateway 에서 토큰에 대한 검증과 securityConfig를 설정한 다음 처리하는 방향으로.

이제 기존 구현한 코드를 도메인 별로 전부 분할한다. 그리고 SecurityConfig, JWTUtil같은 토큰과 인증 관련 코드는 전부 지우고 도메인 별로 기능을 정리한다.

2. API Gateway 만들기

API Gateway는 Spring cloud와 Netflix Eureka를 이용했다. webFlux을 적용해 비동기 처리도 지원한다.

  1. 클라이언트 → API Gateway: 클라이언트가 JWT 토큰을 포함하여 API Gateway에 요청을 보냄
  2. API Gateway에서 JWT 검증: API Gateway는 JWT 토큰을 검증하고 검증된 사용자 정보를 헤더에 추가
  3. Eureka 서버로의 서비스 디스커버리: API Gateway는 부팅 시 Eureka 서버에서 마이크로서비스의 위치를 조회하여 캐시
  4. API Gateway → 마이크로서비스: API Gateway는 요청을 적절한 마이크로서비스로 전달
  5. 마이크로서비스에서 요청 처리: 마이크로서비스는 전달된 요청을 처리

API Gateway 서비스에 JWT 토큰의 검증 로직을 포함하여 검증 로직을 통과한 요청만 마이크로 서비스로 보낼 때 헤더에 사용자의 이메일 정보를 헤더에 담아 마이크로 서비스에 전달 → 각 마이크로 서비스는 검증된 이메일을 신뢰하고 해당 이메일로 각 요청을 처리한다.

return chain.filter(exchange.mutate()
                                .request(exchange.getRequest().mutate()
                                        .header("Authenticated-User", email)
                                        .build())
                                .build())
                        .contextWrite(ReactiveSecurityContextHolder.withAuthentication(auth));

헤더의 토큰을 검증하는 방식이 아닌, 헤더에 포함된 이메일로 로직을 처리할 수 있게 각 마이크로 서비스의 로직을 변경했다.

  • 그래서 일단 각 마이크로서비스의 securityConfig에서 permitAll()로 다 뚫어놓긴 했다 (클라이언트가 각 서버 직통 포트로 요청 보낼 일은 없다는 조건을 상정하였으나, 이 부분은 더 공부해야 할 것 같다.)

3. 서비스 간 통신 (비동기)

Kafka 사용하기

왜 Kafka를 선택했는가?

  • 비동기 통신은 서비스 간의 결합도를 낮추고, 서비스가 독립적으로 작동할 수 있게 한다. 이는 MSA가 추구하는 방향과 같다.
  • Kafka는 마이크로서비스 간의 비동기 통신을 지원하여 시스템의 유연성과 확장성을 향상시킬 수 있다.
  • Kafka는 높은 처리량과 확장성을 제공하는 분산 스트리밍 플랫폼이며, 파티션을 통해 데이터 처리를 병렬로 수행**수 있다.

Event란 비즈니스에서 일어나는 모든 일 (데이터)을 의미한다. 3가지 특징을 갖고 있다.

  1. 이벤트 스트림을 안전하게 전송한다. (Pub & Sub 기능)
  2. 이벤트 스트림을 디스트에 저장한다. (다른 이벤트 스트림과의 차별점)
  3. 대용량의 실시간 이벤트 스트림을 분석 및 처리 기반으로 사용한다. (대용량 처리가 가능함으로 이 데이터를 추출해서 분석 및 처리가 가능)

카프카 기본 개념

  • 토픽: 카프카 안에 메시지가 저장되는 장소
  • 프로듀서 : 메세지를 생성해서 토픽으로 보내는 애플리케이션
  • 컨슈머 : 토픽의 메세지를 가져와서 활용하는 애플리케이션

카프카 구성 요소

카프카는 크게 프로듀서, 카프카 클러스터(+브로커), 주키퍼, 컨슈머로 구성되어있다.

  • 카프카 브로커: 파티션에 대한 Read, Write를 관리하는 소프트웨어. 하나의 클러스터는 최소 4대이상의 브로커로 구성되길 권장함.
  • 주키퍼: 브로커를 관리(브로커들의 목록/설정)하는 소프트웨어. 하지만 현재 카프카 3부터는 주피커 대신 KRaft로 카프카 클러스터 내부에 브로커 관련 메타 데이터를 관리하도록 설정할 수 있다.

카프카는 병렬 처리 시스템으로 파티션이 1개가 아니라면 모든 메세지에 대한 전체 순서를 보장하기 어렵다. 파티셔널을 통해 key에 의하여 분산되어 들어가기 때문이다. 하지만 실제 시스템에서 모든 데이터에 대한 순서를 보장할 필요가 없다. 특정 고객 또는 특정 키의 데이터의 순서만 보장받으면 되기 때문이다. 즉, 키에 대한 순서가 보장됨으로 이 부분에 대한 문제는 멀티 파티션을 이용하는데 이슈가 되지 않는다. 단, 운영 중에 파티션 개수를 변경하게 되면 순서를 보장받기 어렵다. 이 점을 반드시 기억해야 함.

→ 내 프로젝트에서 Payment에서 발행하는 모든 이벤트는 파티션 1개로 구독하게 할 것이다. 특정 키 없이 요청 순서가 보장되어야 하기 때문이다.

judy

About judy

junior BE

Comments

comments powered by Disqus