본문 바로가기
해피 코딩/Spring

[MSA] API 게이트웨이 Spring Cloud Gateway

by happy-coding 2024. 8. 5.
🔥 SpringCloudGateway를 이해하고 동작해 보기

[  API 게이트웨이의 주요 기능 ]

  • 라우팅: 클라이언트 요청을 적절한 서비스로 전달
  • 인증 및 권한 부여: 요청의 인증 및 권한을 검증
  • 로드 밸런싱: 여러 서비스 인스턴스 간의 부하 분산
  • 모니터링 및 로깅: 요청 및 응답을 로깅하고 모니터링
  • 요청 및 응답 변환: 요청과 응답을 변환하거나 필터링

[ Spring Cloud Gateway ]

  • Spring 프로젝트의 일환으로 개발된 API 게이트웨이로, 클라이언트 요청을 적절한 서비스로 라우팅하고 다양한 필터링 기능을 제공합니다.
  • Spring Cloud Netflix 패키지의 일부로, 마이크로서비스 아키텍처에서 널리 사용됩니다.

[ Spring Cloud Gateway의 주요 특징 ]

  • 동적 라우팅: 요청의 URL 패턴에 따라 동적으로 라우팅
  • 필터링: 요청 전후에 다양한 작업을 수행할 수 있는 필터 체인 제공
  • 모니터링: 요청 로그 및 메트릭을 통해 서비스 상태 모니터링
  • 보안: 요청의 인증 및 권한 검증

사진 toss.tech


[ Spring Cloud Gateway 설정 ]

gateway의 yaml 설정
server:
  port: 19091

spring:
  main:
    web-application-type: reactive  # Spring 애플리케이션이 리액티브 웹 애플리케이션으로 설정됨
  application:
    name: gateway-service  # 애플리케이션 이름을 'gateway-service'로 설정
  cloud:
    gateway:
      routes:  # Spring Cloud Gateway의 라우팅 설정
        - id: order-service  # 라우트 식별자
          uri: lb://order-service  # 'order-service'라는 이름으로 로드 밸런싱된 서비스로 라우팅
          predicates:
            - Path=/order/**  # /order/** 경로로 들어오는 요청을 이 라우트로 처리
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/product/**
        - id: auth-service
          uri: lb://auth-service
          predicates:
            - Path=/auth/signIn
      discovery:
        locator:
          enabled: true  # 서비스 디스커버리를 통해 동적으로 라우트를 생성하도록 설정

eureka:
  client:
    service-url:
      defaultZone: http://localhost:19090/eureka/  # Eureka 서버의 URL을 지정

service:
  jwt:
    secret-key: "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"
Dependencies


[ Spring Cloud Gateway 필터링 ]

  • 필터 종류
    • Global Filter: 모든 요청에 대해 작동하는 필터
    • Gateway Filter: 특정 라우트에만 적용되는 필터
  • 필터 구현
    • 필터를 구현하려면 GlobalFilter 또는 GatewayFilter 인터페이스를 구현하고, filter 메서드를 오버라이드해야 합니다.

Pre Filter
  1. Pre 필터는 요청이 처리되기 전에 실행됩니다.
  2. 따라서 Pre 필터에서는 요청을 가로채고 필요한 작업을 수행한 다음, 체인의 다음 필터로 요청을 전달합니다.
  3. 이때, 추가적인 비동기 작업을 수행할 필요가 없기 때문에 then 메서드를 사용할 필요가 없습니다.
@Component
public class CustomPreFilter implements GlobalFilter, Ordered {
  private static final Logger logger = Logger.getLogger(CustomPreFilter.class.getName());

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request = exchange.getRequest();
    logger.info("Pre Filter: Request URI: " + request.getURI());
    // 다음 필터로 전달
    return chain.filter(exchange);
  }

  @Override
  public int getOrder() {
    // 필터 순서를 가장 높은 우선 순위로 설정
    return Ordered.HIGHEST_PRECEDENCE;
  }
}
Post Filter
  1. Post 필터는 요청이 처리된 후, 응답이 반환되기 전에 실행됩니다.
  2.  Post 필터에서는 체인의 다음 필터가 완료된 후에 실행되어야 하는 추가적인 작업을 수행해야 합니다. 
  3. 따라서 chain.filter(exchange)를 호출하여 다음 필터를 실행한 후, then 메서드를 사용하여 응답이 완료된 후에 실행할 작업을 정의합니다.
@Component
public class CustomPostFilter implements GlobalFilter, Ordered {
  private static final Logger logger = Logger.getLogger(CustomPreFilter.class.getName());

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return chain.filter(exchange).then(Mono.fromRunnable(()->{
      ServerHttpResponse response = exchange.getResponse();
      logger.info("Post Filter : Response status code is " + response.getStatusCode());
    }));
  }

  @Override
  public int getOrder() {
    // 필터 순서를 가장 낮은 순위로 설정
    return Ordered.LOWEST_PRECEDENCE;
  }
}

[ Run ]

  • 실행 순서: 유레카 서버, 게이트웨이, 주문,  상품 순으로 어플리케이션을 실행합니다.
  •  유레카 + 클라우드 게이트웨이 + Order 인스턴스(1개) + Product 인스턴스(2개) 로 진행해봅니다.
http://localhost:19090에 접속하여 각 인스턴스를 확인합니다.


SpringCloudGateway 적용 전
  • Order와 Product가 본인의 호스트 주소를 통하여 접근하는 것을 볼 수 있습니다.


SpringCloudGateway 적용 후
  • SpringCloudGateway의 포트 번호인 '19091' 을 통해서 접근하는 모습을 볼 수 있습니다.


그림으로 이해하기


SpringCloudGateway를 학습하며 궁금했던 부분이 해결되었다. 앞선 MSA를 공부하면서 "호스트가 모두 다르면 관리가 힘힘들지 않을까?"라는 생각을 했었는데 오늘 SpringCloudGateway를 학습하며 궁금증이 해결이 되었다.

 

읽어 주셔서 감사합니다 😊