Spring Boot/MSA

Spring Boot MSA GateWay 설정

최-코드 2024. 4. 26. 14:37

GateWay 특성 : Eureka, Config, spring boot application와 같은 서비스들은 블로킹 기반으로 모두 톰캣 엔진을 사용했지만, 게이트웨이의 경우 비즈니스 로직 처리보단 단순하게 지나가는 통로로서 I/O 처리를 중점적으로 진행하기 때문에 논 블로킹 방식으로 동작하는 WebFlux와 네티엔진을 사용한다.

cf) 함수A는 함수B에게 제어권을 주지 않고, 자신의 코드를 계속 실행한다(논블로킹), 하지만, A함수는 B함수의 리턴 값이 필요하기 때문에, 계속 함수B에게 함수 완료 여부를 물어본다.(동기)

 

마이크로서비스들의 공통 기능, 예를 들어 인증, 권한 부여, 로킹, 속도 제한 등은 보통 API 게이트웨이에 구현한다.

 

프로젝트 생성 시에 필수적인 의존성으로는 spring cloud routing reactive gateway가 있다. 그냥 gateway로 하면 안 된다.

 

각각의 요청에 맞는 마이크로서비스에 보내는 것을 라우팅이라고 하는데 이 라우팅은 게이트웨이 설정 통해 이뤄진다. 

 

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

 

Spring Cloud Gateway

This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 6, Spring Boot 3 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them

docs.spring.io

5장을 보면 다양한 라우팅 설정 방식이 있다.

 

아래는 gateway 서버의 설정 파일이다.

spring.application.name=api-gateway

server.port=8765

#게이트웨이와 Eureka 서버 연동 이유 : MSA를 구성하는 요소는 자동으로 스케일링이 되기 때문에
#새로 생긴 서버의 IP를 게이트웨이가 알지 못한다. 따라서 Eureka 서버가 해당 목록들을 관리하며
#게이트웨이에 전달한다.
eureka.client.service-url.defaultZone=http://localhost:8761/eureka

#gateway가 eureka로부터 인스턴스 정보를 조회하여 포워딩할 수 있도록 설정
spring.cloud.gateway.discovery.locator.enabled=true

#애플리케이션 이름을 소문자로 써도 동작 가능하도록 설정 원래는 eureka 서버에서 보이는 그대로 해야함
spring.cloud.gateway.discovery.locator.lower-case-service-id=true

 

아래는 config class에 저장한 path 방식의 라우팅 방식이다.

@Configuration
public class RouteConfig {

    @Bean
    public RouteLocator garewayRouter(RouteLocatorBuilder builder) {
        return builder.routes()
                //localhost:8756/get이 http://httpbin.org:80으로 포워딩된다.
                .route(predicateSpec -> predicateSpec.path("/get")
                		//filters를 통해 포워딩할 때 붙일 헤더나 파라미터를 붙인다.
                        .filters(filterSpec -> filterSpec.addRequestHeader("Header", "Hvalue")
                                .addRequestParameter("Param", "Pvalue"))
                        .uri("http://httpbin.org:80"))
                .route(predicateSpec -> predicateSpec.path("/currency-exchange/**")
                        /*
                            lb://가 붙으면 /currency-exchange/로 시작하는 요청을 Eureka를 통해 인스턴스를 조회하고,
                            로드밸런싱을 수행하면서 포워딩된다.
                            클라이언트 자체에 로드 밸런싱을 수행하는 알고리즘이 내제되어 있다.
                            (Cloud LoadBalancer 의존성으로 인해)
                        */
                        .uri("lb://currency-exchange"))
                .route(p -> p.path("/currency-conversion/**")
                        .uri("lb://currency-conversion"))
                .route(p -> p.path("/currency-conversion-feign/**")
                        .uri("lb://currency-conversion"))
                .build();
    }
}