[Spring Cloud로 개발하는 MSA] API Gateway Service

유호빈·2024년 3월 27일
0

MSA

목록 보기
3/10

인프런의 "Spring Cloud로 개발하는 마이크로서비스" 강의를 보고 작성되었습니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4

1. API Gateway Service

마이크로소프트에서 클라우드 아키텍처를 보여주는 그림으로, 클라이언트에서 직접 Microservices를 호출하는 모습입니다.
이렇게 직접 호출을 하게되면 microservice가 추가 혹은 변경 사항이 생기면 클라이언트쪽에서도 엔드포인트에 대해 수정하고 배포할 필요가 생깁니다.

API Gateway Service 역할

API Gateway Service는 사용자가 설정한 라우터의 엔드포인트로 클라이언트를 대신해 요청한 후 받은 응답을 클라이언트에 전달해주는 프록시 역할을 합니다.

그림과 같이 API Gateway에서 microservice로 요청되는 모든 정보를 일괄처리하게 되어 시스템의 내부 구조를 숨기고, 외부 요청에 대해 적절한 형태로 가공해 응답이 가능하게 됩니다.

API Gateway 사용 시 장점

  • 인증 및 권한 부여 : 게이트웨이에서 단일 작업이 진행 가능하게 됩니다.
  • 서비스 검색 통합
  • 응답 캐싱
  • 정책, 회로 차단기 및 QoS 다시 시도 : 문제 발생 시 회로를 차단하고, 네트워크 트래픽 처리를 다시 시도합니다.
  • 속도 제한
  • 부하 분산
  • 로깅, 추적, 상관 관계 : 어느 microservice가 누구에 의해 호출되었는지, 어디서 진입하고, 어느 이동 경로를 거치는 지 등을 추적 및 로그를 기록합니다.
  • 헤더, 쿼리 문자열 및 청구 변환
  • IP 허용 목록에 추가 : 허용 혹은 차단 IP를 확인하는 방화벽 역할을 합니다.

Spring Cloud에서 MSA 간 통신 방법

1) RestTemplate

서버 주소와 포트, 전달할 파라미터, 메소드의 방식을 외부에 전달하는 형태입니다.

2) Feign Client

특정 인터페이스를 생성해서 외부 서비스의 이름을 등록합니다. 등록된 microservice의 이름으로 호출이 가능하게 됩니다.

초기 Spring Cloud의 Load Balancer

  • Ribbon

초기 Spring Cloud에서는 Client Side Load Balancer인 Ribbon을 제공했습니다.
Ribbon은 서비스의 이름으로 호출이 가능하지만, 비동기 처리가 잘 되지 않는 문제가 있어 최근 사용이 되지 않아 Spring Boot 2.4에서 Maintenance 상태입니다.

  • Netfilx zuul

Load Balancer 역할을 하지만, 역시 비동기 처리가 잘 되지 않기 때문에 현재는 Maintenance 상태입니다.

2. Spring Cloud Gateway

위의 두 Load Balancer는 비동기 방식 처리의 어려움으로 비동기 처리가 가능한 Spring Cloud Gateway를 사용해보려 합니다.

프로젝트 생성

  • Dependencies

DevTools, Eureka Discovery Client, Gateway 를 추가해 주었습니다.

gateway는 다음과 같이 gateway-mvc가 아닌 의존성을 추가해주어야 Tomcat 서버가 아닌 비동기 방식을 사용하는 Netty 서버로 연결이 됩니다.

  • application.yml 파일 설정

  1. cloud.gateway.routes : 리스트 형태로 라우트 객체를 등록합니다.

  2. predicates : 라우터의 조건을 설정합니다.

클라이언트가 조건에 맞는 요청을 하게 되면 uri로 라우팅을 합니다.
이때, Path가 그대로 uri에 붙기 때문에 컨트롤러에서 매핑을 등록할 필요가 있습니다.

3. Spring Cloud Gateway Filter 적용

게이트웨이 내부

  • Gateway Handler Mapping : 클라이언트로부터 어떤 요청이 들어왔는지 요청 정보를 확인
  • Predicate : 조건 분기
  • Pre / Post Filter : 요청 정보 구성

1) 자바 코드로 FilterConfig.java 등록

이와 같이 RouterLocator Bean을 등록하게 되면 application.yml에 등록한 라우터를 자바 코드를 통해 작성 가능합니다.
여기서는 람다식을 통해 인자의 path를 확인 후 request, response 헤더를 설정해 uri로 이동시킵니다.

  • 헤더 확인 - Controller에 헤더 확인 추가

localhost:8000/first-service/message 호출 시 로그 확인 가능합니다.

2) application.yml 파일로 filter 추가

위의 자바 코드로 작성한 필터 설정을 yml 파일에서 filters를 통해 등록할 수 있습니다.

4. Custom Filter

Custom Filter를 등록해 사용자 정의의 필터로 로그, 인증 등의 역할을 수행할 수 있습니다.

request id와 response status code를 로그로 남기는 필터입니다.

  • exchange, chain 형태를 반환해줍니다.
  • Netty를 사용하기 때문에 ServletRequest 대신 비동기 방식인 ServerRequest를 사용합니다.
  • 위에 사용된 Mono.fromRunnable()은 어떤 파라미터도 받지 않고, 어떤 값도 리턴하지 않는 메소드입니다.

application.yml에 Custom Filter 등록

위와 같이 cloud.gateway.routes의 filters에 CustomFilter를 등록합니다.

5. GlobalFilter

각 라우터가 실행될 때 공통적으로 시행될 수 있는 필터로, 과정상 모든 필터의 가장 먼저 시작되고 마지막에 종료됩니다.

1) GlobalFilter 설정

2) application.yml에 GlobalFilter 등록

gateway에 default-filters로 설정합니다.

  • args의 Config 정보에 같은 이름의 값으로 매핑됩니다.

현재는 yml 파일이 microservice에 내장되는 데이터로, 변경이 일어나면 다시 빌드하고 배포하는 과정을 거쳐야하는데, 이후 진행하는 강의에서 외부 데이터를 가져와 반영합니다.

3) postman test

postman을 통해 진행한 테스트를 보면 컨트롤러가 정상 동작하고, CustomFilter와 GlobalFilter의 로그가 정상적으로 찍히는 모습을 볼 수 있습니다.

6. Logging Filter

GlobalFilter를 응용해서 로그를 출력하는 Filter를 구현해보았습니다.

총 3개의 Filter가 적용된 프로젝트의 전체적인 흐름은 다음과 같습니다.

LoggingFilter 구현

GlobalFilter와 동일하게 apply 메소드를 정의하여 구현하였지만, 반환 값인 GatewayFilter를 인터페이스이기 때문에 인스턴스 생성이 불가하므로 new OrderedGatewayFilter를 사용해 구현했습니다.

OrderdedGatewayFilter 내부의 filter라는 메소드가 재정의 됨으로 필터가 해야할 역할을 정의할 수 있고, filter 메소드는 OrderdedGatewayFilter의 생성자의 GatewayFilter의 filter를 구현하는 것입니다.

GatewayFilter의 filter메소드의 argument로 exchange와 chain을 받고 있어 위의 람다식에서 exchange와 chain을 통해 filter 메소드를 구현한 것으로 생각합니다.

application.yml에 LoggingFilter 추가

filters에 추가적으로 전달할 파라미터가 생기면 각 필터에 name 옵션을 추가해 주어야 합니다.

7. Load Balancer

위에서 구현한 Spring Cloud Gateway와 이전 포스팅에서 만든 Eureka를 연동시켜 Load Balancer의 역할을 하도록 만들었습니다.

Spring Cloud Gateway를 Eureka Server에 등록

1) Gateway에 Eureka Client 추가

2) application.yml에 라우팅 정보 등록

uri 부분을 lb://(discovery service에 등록된 이름) 으로 변경해 포워딩 시킬 수 있습니다.

3) Eureka 서버에 등록된 서비스 확인

구현한 동일한 Service를 여러개 기동시키기

이 부분은 앞서 포스팅에서 설명한 부분으로 간단하게 설명하면
port를 0으로 설정해 랜덤 포트로 변경한 후 intance-id를 추가해 microservice가 구분되도록 설정합니다.

Controller에 서비스에 랜덤으로 설정된 포트를 확인하는 로직을 구현하였습니다.

이후 postman으로 호출하게 되면 다음과 같이 라운드로빈 방식으로 게이트웨이가 서비스를 호출하게 됩니다.


profile
시작하자

0개의 댓글