개요

Spring Cloud Gateway는 Spring 생태계의 공식 API Gateway 솔루션으로, Spring WebFlux 기반의 논블로킹 아키텍처로 설계되었습니다. Netflix Zuul의 후속으로 자리잡았으며, 라우팅, 필터링, 로드밸런싱, 서킷브레이커 등 API Gateway의 핵심 기능을 제공합니다. MSA 환경에서 단일 진입점(Single Entry Point)을 구축할 때 가장 널리 사용되는 선택지입니다.

핵심 개념

Route(라우트)는 게이트웨이의 기본 빌딩 블록입니다. 각 라우트는 ID, 목적지 URI, Predicate 집합, Filter 집합으로 구성됩니다. 요청이 Predicate 조건을 만족하면 해당 라우트로 매칭됩니다.

Predicate(프레디케이트)는 HTTP 요청의 속성(경로, 헤더, 메서드, 쿼리 파라미터 등)을 기반으로 라우트 매칭 조건을 정의합니다.

Filter(필터)는 요청/응답을 가로채서 수정할 수 있습니다. 인증 헤더 추가, 요청 로깅, Rate Limiting 등의 크로스커팅 관심사를 처리합니다.

Service Discovery와 연동하면 하드코딩된 URI 대신 서비스 이름으로 라우팅할 수 있어, 인스턴스 변경에 유연하게 대응합니다.

실전 예제

기본적인 게이트웨이 설정입니다.

# application.yml
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://USER-SERVICE
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1
            - name: CircuitBreaker
              args:
                name: userServiceCB
                fallbackUri: forward:/fallback/users

        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/api/orders/**
            - Method=GET,POST,PUT
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@userKeyResolver}"

      default-filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY

JWT 인증을 처리하는 커스텀 Global Filter를 구현합니다.

@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {

    private final JwtTokenProvider tokenProvider;

    private static final List<String> OPEN_ENDPOINTS = List.of(
        "/api/auth/login", "/api/auth/register", "/health"
    );

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();

        if (OPEN_ENDPOINTS.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }

        String token = extractToken(exchange.getRequest());
        if (token == null || !tokenProvider.validateToken(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String userId = tokenProvider.getUserId(token);
        ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
            .header("X-User-Id", userId)
            .header("X-User-Roles", tokenProvider.getRoles(token))
            .build();

        return chain.filter(exchange.mutate().request(mutatedRequest).build());
    }

    private String extractToken(ServerHttpRequest request) {
        String bearer = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (bearer != null && bearer.startsWith("Bearer ")) {
            return bearer.substring(7);
        }
        return null;
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

Rate Limiter를 위한 KeyResolver 설정입니다.

@Configuration
public class RateLimiterConfig {

    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> {
            String userId = exchange.getRequest().getHeaders()
                .getFirst("X-User-Id");
            return Mono.justOrEmpty(userId)
                .defaultIfEmpty(exchange.getRequest()
                    .getRemoteAddress().getAddress().getHostAddress());
        };
    }
}

활용 팁

  • Spring Cloud LoadBalancer: lb:// 스킴을 사용하면 Eureka 또는 Kubernetes Service Discovery와 자동 연동됩니다.
  • Circuit Breaker: Resilience4j와 통합하여 하위 서비스 장애 시 Fallback 응답을 제공하세요.
  • CORS: 게이트웨이 레벨에서 CORS를 설정하면 각 마이크로서비스에서 중복 설정할 필요가 없습니다.
  • 로깅: spring.cloud.gateway.httpserver.wiretap=true 설정으로 요청/응답 상세 로그를 확인할 수 있습니다.
  • 테스트: WebTestClient를 사용하여 게이트웨이 라우팅과 필터를 통합 테스트하세요.

마무리

Spring Cloud Gateway는 MSA 환경에서 API Gateway의 표준으로 자리잡았습니다. YAML 기반의 선언적 설정과 코드 기반의 프로그래밍 방식을 모두 지원하여 유연하게 구성할 수 있습니다. 인증, Rate Limiting, Circuit Breaker 등 크로스커팅 관심사를 게이트웨이에서 통합 관리하면 각 마이크로서비스의 비즈니스 로직에 집중할 수 있습니다.