PSD( Private-Self-Development )

API Gateway 본문

Backend/MSA

API Gateway

chjysm 2024. 3. 26. 20:28

API Gateway 란?

사용자가 설정한 라우팅 설정에 따라서 각각의 엔드포인트에 요청을 대신 보내주고 응답을 대신 받아서 이를 전달하는 프록시 역할을 수행한다. 

 

MSA 에 해당 구조가 사용되는 이유는 

클라이언트에서 각각의 micro service 를 직접 호출하게 되면 

micro service 에 수정사항이 생기면 각각의 클라이언트가 모두 수정되야 하므로 

이를 방지하기 위해 사용한다.

 

API Gateway 의 기능

  • 인증 및 권한 부여 
  • 서비스 검색 통합
  • 응답 캐싱
  • 정책, 회로 차단기(서비스 문제 생긴 경우) 및 Qos 다시 시도
  • 속도 제한
  • 부하 분산( Load Balancing )
  • 로깅, 추적, 상관 관계
  • 헤더, 쿼리 문자열 및 청구 변환
  • IP 허용 목록에 추가

 

Netflix Rebbon (Deprecated)

  • Client Side Load Balancer
  • 서버가 아닌 클라이언트에서 사용한다.
  • MSA 이름으로 호출 가능
  • 비동기 처리가 불가능하므로 잘 사용하지 않는다.

 

Netflix zuul (Deprecated)

  • Server Side Load Balancer

 

Spring Cloud Gateway

  • 사용 권장

 

구현

1.  Dependency 추가

implementation 'org.springframework.cloud:spring-cloud-starter-config'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

 

2.  yml 파일 설정

server:
  port: 8000

# Service Discovery 에 게이트 웨이 등록
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka


# Service Discovery 사용 안하는 경우
Spring:
  application:
    name: apigateway-service
  cloud:
    gateway:
      # yml 에서 필터 및 라우팅 설정
      routes:
        - id: first-service
          uri: http://localhost:8081/
          predicates:
            - Path=/first-service/**
          filters:
            # 헤더값 추가
            - AddRequestHeader = first-request, first-requests-header2
            - AddResponseHeader = first-response, first-response-header2
            # 커스텀 필터 적용
            - CustomFilter
        - id: second-service
          uri: http://localhost:8082/
          predicates:
            - Path=/second-service/**
          filters:
            # 헤더값 추가
            - AddRequestHeader = first-request, first-requests-header2
            - AddResponseHeader = first-response, first-response-header2
            # 커스텀 필터 적용
            - CustomFilter
            # 커스텀 필터 적용 (매개 변수 사용)
            - name: loggingFilter
              args:
                baseMessage: Spring Cloud Gateway GlobalFilter
                preLogger: true
                postLogger: true
      # 공통 필터 설정
      default-filters:
        - name: GlobalFilter
          args:
            baseMessage: Spring Cloud Gateway GlobalFilter
            preLogger: true
            postLogger: true

# Service Discovery 사용 하는 경우
Spring:
  cloud:
    gateway:
      routes:
        - id: first-service
          uri: lb://MY-FIRST-SERVICE # 로드 밸런서:서비스 이름 => 이러면 Service Discovery 에서 자동으로 로드 밸런서 동작을 한다.
          predicates:
            - Path=/first-service/**
          filters:

 

 

3.  java 코드를 이용한 필터 및 라우터 추가

/**
 * 자바 코드를 이용한 필터 적용
 * */
@Configuration
public class FilterConfig {
    @Bean
    public RouteLocator gatewayRoutes(RouteLocatorBuilder builder){
        return builder.routes()
                .route( r -> r.path("/first-service/**")
                        .filters( f -> f.addRequestHeader("first-request", "first-request-header")
                                .addResponseHeader("first-response", "first-response-header")
                        )
                        .uri("http://localhost:8081/")
                )
                .route( r -> r.path("/second-service/**")
                        .filters( f -> f.addRequestHeader("second-request", "second-request-header")
                                .addResponseHeader("second-response", "second-response-header")
                        )
                        .uri("http://localhost:8082/")
                )
                .build();
    }
}

 

4.  커스텀 필터 구현

/**
 * 커스텀 필터
 * 각각의 라우터 정보에 맵핑 필요
 * */
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {

    public CustomFilter(Class<Config> configClass) {
        super(configClass);
    }

    public static class Config{
        // Config Info
    }

    @Override
    public GatewayFilter apply(Config config) {
        // 기본
        return (exchange,chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            log.info("Custom PRE filter: request ID -> {}", request.getId());
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                log.info("Custom POST filter: response code -> {}", response.getStatusCode());
            }));
        };

        // 우선 순위 설정 가능
        GatewayFilter filter = new OrderedGatewayFilter((exchange,chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            log.info("Custom PRE filter: request ID -> {}", request.getId());
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                log.info("Custom POST filter: response code -> {}", response.getStatusCode());
            }));
        }, Ordered.HIGHEST_PRECEDENCE);
        return filter;
    }
}

 

5.  글로벌 필터 구현

@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {

    public GlobalFilter(Class<Config> configClass) {
        super(configClass);
    }

    @Data
    public class Config {
        private String baseMessage;
        private boolean preLogger;
        private boolean postLogger;
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            log.info(config.getBaseMessage());
            if(config.isPreLogger()){
                log.info(request.getId());
            }

            return chain.filter(exchange).then(Mono.fromRunnable( () -> {
                if(config.isPostLogger()){
                    log.info(response.getStatusCode() + "");
                }
            }));
        };
    }
}

 

Service Discovery 와 API Gateway 연동

 

'Backend > MSA' 카테고리의 다른 글

Kafka( 카프카 )  (0) 2024.04.22
Feign Client  (1) 2024.04.19
Spring Cloud Config  (0) 2024.04.16
Service Discovery  (1) 2024.01.09
MSA  (0) 2024.01.09