API Gateway

김성환·2022년 8월 19일
1

MSA

목록 보기
3/7

API Gateway란

사용자가 설정한 라우팅설정에 따라서 각각의 엔드포인트(일반적으로 HOST를 의미하지만 msa구조에서는 micro서비스를 의미한다)로 클라이언트를 대신해 요청하고 응답을 받으면 다시 클라이언트로 보내주는 프록시 역활을 하는 서비스이다.
※ 참고로 라우팅이란 어떤 네트워크 안에서 데이터를 최적의 경로를 선택하는 과정을 말한다.

API Gateway가 사용되는 이유

클라이언트가 직접 micro서비스의 주소로 매핑되어 있다면, 새로운 micro서비스가 추가될 때마다, 클라이언트의 코드 등이 수정 배포되어야 한다. (수정 배포에 취약하다)

API Gateway의 기능

  • 인증,권한 부여
  • 마이크로 서비스 검색 통합
  • 속도 제한
  • 부하 분산(로드밸런서)
    등등

spring cloud에서 micro서비스간 통신을 구현하기 위한 방법

  1. RestTemplate : 하나의 애플리케이션에서 다른 애플리케이션을 호출할때 많이 사용되는 api
  2. Feign Client

Spring Cloud Gateway란?

Spring Cloud Gateway는 Spring Reactive 생태계 위에 구현된 API Gateway이다.
또한 비동기방식으로 서비스가 실행되기 때문에 Netty라는 내장 서버(tomcat 대신)를 사용하게 된다.
Spring cloud gateway의 경우 mvc구조가 아닌 webflux구조로 이루어져있다.
※ webflux구조란 서버에서 reactive 스타일의 애플리케이션 개발을 도와주는 모듈이다.
※ Reactive Programming이란? 다양한 소스에서 들어오는 데이터의 흐름(스트림)을 비동기적으로 합쳐서 이런 문제를 해결하는 프로그래밍을 의미(여기서 문제란 ms단위의 응답시간 요구가 있다(즉, 속도))
https://juneyr.dev/reactive-programming

Spring Cloud Gateway의 구조

Spring Cloud Gateway안에서는 크게 predicate와 filter로 구분된다.
predicateGateway Handler Mapping , Gateway Web Handler로 구성되어 있다.

  • Gateway Handler Mapping은 클라이언트의 요청이 경로(라우터에서 설정한 경로)와 일치하는지 판단해주는 역활
  • Gateway Web Handler은 판단된 요청과 관련된 필터로 해당 요청을 전송해주는 역활
  • filter는 pre filter와 post filter로 나눠지며, pre 필터가 먼저 실행된다.
    이후 프록시 요청이 실행되며, post필터가 실행되고 클라이언트에게 응답된다.
  • predicate를 조건문이라고 생각하면 된다.
    predicate에 여러 조건들(Path, Cookie, After, Header 등등)을 추가하여 들어오는 요청에 대한 판단을 할 수 있다.

Spring Cloud Gateway 과정


위의 그림은 좀 더 세부적인 스프링 클라우드의 게이트웨이 구조를 그린 것이다.(ODODODODO님의 그림을 가져옴)
위와 같은 과정을 거치게 된다. 중요부분을 요약하면 다음과 같다.

  • HttpWebHandlerAdapter : 클라이언트의 요청과 응답을 ServerWebExchange객체로 생성해주는 역활을 한다.
    (기존 MVC구조에서는 요청과 응답에 대한 값을 HttpServletRequest와 같은 객체를 이용했다. 하지만 webflux의 경우 ServerWebExchange객체를 사용하게 된다.)
  • RoutePredicateHandlerMapping : Gateway Handler Mapping을 담당하는 것으로 lookupRoute() 메서드를 통해 Route마다 설정된 Predicate(yml파일에서 적용한)를 적용해 알맞은 Route instance를 찾는다.(이 의미는 곧 요청에 대한 handler를 찾아준다는 의미이다.)
  • DispatcherHandler : 요청에 대한 처리(handle)를 찾게 하고(RoutePredicateHandlerMapping에게 시킴) 그에 대한 결과(FilteringWebHandler : 요청을 처리할 핸들러 객체)를 처리해주는 역활
  • 참고 그림 : https://dlsrb6342.github.io/2019/05/14/spring-cloud-gateway-%EA%B5%AC%EC%A1%B0/

Spring Cloud Gateway Filter

필터는 클래스를 정의하여 필터를 설정하는 방법과 yml파일을 이용해 필터를 설정하는 방법이 존재한다.
필터의 경우 global필터와 custom(혹은 내장)필터로 구분된다.
yml파일 작성방법은 custom필터의 경우 cloud.gateway.routes.filters에 작성해야 하며, cloud.gateway.default-filters에 작성해야 한다.

  • global필터 : 서비스에 공통적으로 적용할 필터를 의미한다. 그렇기 때문에 먼저 실행이 된다.
  • custom필터 : 각각의 서비스에 적용될 필터를 의미한다.
    필터는 args라는 속성을 이용해 필터에 사용될 매개변수들을 사용할 수 있다.

AbstractGatewayFilterFactory

사용자가 정의한 필터를 구현하기 위해 상속받는 클래스로 yml파일의 args의 값을 받기 위해 제네릭을 사용하여 해당 args의 값을 담을 클래스를 만들어 사용하게 된다.
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config>
이때, args의 클래스는 static class로 만들어 사용한다.

Filter의 순서

필터들의 순서는 global -> custom 순으로 실행이 된다.
filter의 경우 OrderedGatewayFilter를 직접 구현할 경우 필터의 순서를 정할 수 있다.
AbstractGatewayFilterFactory의 경우 apply메서드를 구현해야 하는데, 이때, apply메서드의 리턴값이 GatewayFilter이다. 이때, OrderedGatewayFilter는 GatewayFilter를 구현한 구현체이기 때문에, 해당 객체를 넣어줄 수 있다.

//  filter에 OrderedGatewayFilter객체를 넣어준다.
// 이때, OrderedGatewayFilter생성자에는 GatewayFilter객체와 int형인 order를 매개변수로 받는다.
// 따라서 GatewayFilter를 구현하기 위한 코드를 작성해준 것이다.
GatewayFilter filter = new OrderedGatewayFilter((exchange,chain)->{
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();
            log.info("Logging filter base Message: {}", config.getBaseMessage());
            if(config.isPreLogger()){
                log.info("Logging PRE filter : request id -> {}", request.getId());
            }
            // Custom Post Filter
            return chain.filter(exchange).then(Mono.fromRunnable(()->{
                if(config.isPostLogger()){
                    log.info("Logging POST filter : response code -> {}", response.getStatusCode());
                }
            }));
        }, Ordered.HIGHEST_PRECEDENCE);

API Gateway만으로도 서버운영이 가능

한데 왜 Service Discovery가 필요할까?
Eureka 와 같은 Service Discovery서비스를 이용하지 않을 경우 개발자가 작성한 micro서비스들의 주소(IP)를 각각 정확하게 작성해 주어야 한다.
하지만 Service Discovery서비스를 이용할 경우 해당 서비스 서버에 클라이언트서버를 등록할 경우 인스턴스 ID나 이름으로 호출할 수 있다. 따라서 추가설정 혹은 IP변경을 해야하는 번거로움을 해결해준다.

profile
개발자가 되고 싶다

0개의 댓글