오늘은 MSA에서 빠질 수 없는 개념인 API Gateway의 역할을 수행하는 Spring Cloud Gateway에 대해 포스팅하려고 합니다. 더불어 Microservice의 IP, Port 정보들을 저장 및 관리해 주는 Eureka Server도 함께 알아보도록 하겠습니다.
Spring Cloud Gateway에 대해 알아보기 전, API Gateway가 무엇인지 설명드리겠습니다.
API Gateway
- 비즈니스 로직이 아닌 기타 관심사들을 처리하는 역할
- 분산 시스템 또는 마이크로서비스 아키텍처에서 매우 중요한 역할을 하는 컴포넌트입니다.
- 클라이언트와 백엔드 서비스 사이에 위치하는 리버스 프록시 역할을 하는 서비스입니다.
- 클라이언트 요청을 여러 마이크로서비스로 분배하고, 이를 중앙에서 관리하는 단일 진입점입니다.
- 기능 단위로 개별 서비스로 분리되었지만, 서비스의 필수 기능은 개별 서비스에서도 동일하게 지원해야 합니다.
- API Gateway는 개별 서비스 앞단에서 모든 서비스들의 endpoint를 단일화해주고, 필수 기능 요소들을 제공해 주는 서비스 역할을 담당합니다.
API Gateway의 주요 기능
- 인증, 인가
- 인증: 사용자의 신원 검증
- 인가: 사용자에게 요청을 실행할 수 있는 권한 부여
- 자체 기능을 구현해서 사용, 별도의 외부 서비스와 연계하여 제공
- API 라우팅
- API의 요청을 식별하여 적절한 마이크로 서비스로 전달
- Qos (Quality of Service)
- 안정적인 서비스 제공, 네트워크 품질 관리를 위해 사용자 / 클라이언트 / API 단위로 접속 제어 가능
- 로깅, 모니터링
- API 요청에 대한 로깅 지원 및 모니터링 기능
- 입력 유효성 검사
- API 요청이 적절한 형식과 필수 데이터를 포함하는지 식별 및 관리하는 기능 제공
이제 API Gateway의 대략적인 개념과 기능에 대해 파악해보았으니, Spring Cloud Gateway에 대한 개념과 구축 과정에 대해서 알아보도록 하겠습니다.
Spring Cloud Gateway (SCG)
- Spring에서 제공하는 오픈소스 기반의 Gateway 서비스
- Netty 기반의 비동기 (Asynchronous) 요청 처리를 제공합니다.
- Spring에서 제공하는 다양한 Component를 조합하여 효율적인 개발이 가능합니다.
Spring Cloud Gateway Component
Route
- client의 요청을 microservices로 routing하는 규칙을 정의합니다.
- 고유 id: route의 고유 식별자
- 목적지 uri: routing할 서비스의 주소 lb://
Predicate
- 주어진 요청이 정의한 조건 경로를 충족하는지 확인하는 구성요소
- 매칭되지 않으면 404 Not Found 응답
Filter
- Spring Cloud Gateway에서 요청이나 응답에서 다양한 전처리, 후처리 작업을 위한 구성요소
- DispatchServlet에 요청이 전달되기 전/후에 url 패턴에 맞는 요청에 부가작업 처리를 위한 컴포넌트
- DispatchServlet: HTTP Protocol로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에게 위임해 주는 프론트 컨트롤러
- Front Controller: 서블릿 컨테이너의 제일앞단에서 서버로 들어오는 모든 요청을 받아서 처리해 주는 컨트롤러
Filter 구축 방법
1. application.yml 설정
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
uri: lb://first-service
predicates:
- Path=/first-service/**
- id: second-service
uri: lb://second-service
predicates:
- Path=/second-service/**
2. 프로젝트 내 FilterConfig 설정
@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();
}
}
Filter Flow
- Client에서 원하는 서비스를 호출하기 위해 Spring Cloud Gateway로 요청을 보냅니다.
- Spring Cloud Gateway에서 어떤 서비스로 가는지 분기 처리를 해줍니다.
- 이때, Gateway HandlerMapping과 Predicate를 거칩니다.
- 이후, Filter (PreFilter, PostFilter)를 거치게 되는데 여기에서 요청정보를 구성할 수 있게 됩니다.
이제 Gateway를 구축할 때, 해당 Component를 application.yml에 정의하면 됩니다.
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
uri: http://localhost:8081/
predicates:
- Path=/first-service/**
filters:
- AddRequestHeader=first-request, first-request-header2
- AddResponseHeader=first-response, first-response-header2
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
- AddRequestHeader=second-request, second-request-header2
- AddResponseHeader=second-response, second-response-header2
Spring Cloud Gateway Architecture
- SCG 내부 구조에서 기능 특성에 따라 Predicate, Filter Chain으로 구분합니다.
- Predicate는 요청받은 API가 지정된 Router 경로에 포함되는지 식별 후 Filter Chain으로 요청을 전달합니다.
- Filter Chain은 각각 하나의 서비스를 제공하는 Filter를 등록하고 사슬과 같이 이어져서 연쇄적으로 Filter가 실행되는 방법
- 백엔드 요청 처리 시점을 기준으로 요청 전에 실행하는 PreFilter, 요청 후에 실행하는 PostFilter로 구분
보통 API Gateway를 구축할 때, Eureka (Service Discovery)를 거쳐 Eureka에 저장된 microservice를 호출하게 됩니다. Eureka에 대해 설명드리겠습니다.
Flow (Client -> SCG -> Eureka -> Microservice)
Eureka Server
- microservice가 다른 microservice를 호출하기 위해 대상 IP, Port가 필요합니다.
- 각 microservice의 IP, Port 정보를 저장하고 검색해주는 Service Discovery가 필요합니다.
- Eureka Server
- 중간 계층 서버의 로드밸런싱 및 장애조치를 목적으로 서비스를 찾기 위해 클라우드에서 사용되는 REST 기반 서비스
- Eureka Client
- Eureka Server에 Microservice를 저장하는 역할
- application.yml에 microservice와 eureka client를 등록해줘야 합니다.
# 실행 포트 지정
server:
port: 8761
spring:
application:
name: discovery-Server
eureka:
client:
register-with-eureka: false
fetch-registry: false
Client
server:
port: 0
spring:
application:
name: my-first-service
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
이렇게 설정해주면, MSA 개발 환경 구축을 위한 Gateway 구축이 완료됩니다. (API Gateway + Eureka)