아래 그림은 서버와 클라이언트가 API Gateway를 통해 통신하는 구조를 보여주는데 처음 보면 다소 복잡해 보일 수 있지만, Gateway는 이 과정을 효율적으로 관리해 준다. API Gateway는 내부 서비스 간 통신을 담당하는 Internal Gateway와 외부 클라이언트 요청을 처리하는 External Gateway로 나누게 되는데, 이번 글에서는 이를 알아보려 한다.

 

API Gateway: MSA 환경에서 External Gateway와 Internal Gateway 차이

모놀리틱 구조에서는 모든 컴포넌트가 하나의 애플리케이션 안에서 동작했었다. 통신 레이어가 필요하지 않았고, 변경 시 시스템 전체에 영향을 미치곤했었다. 그래서 이를 해결하기 위해 MSA(Microservices Architecture) 구조가 도입되었었다.

MSA 구조에서는 클라이언트가 각 서비스 IP를 알아야 하는 문제를 해결하기 위해 API Gateway가 도입된다. Gateway는 클라이언트 요청을 적절한 서비스로 라우팅하며, 보안, 로드 밸런싱, 캐싱 등의 기능을 제공할 수 있다. 

 

Internal Gateway와 External Gateway

내부, 외부 Gateway 를 사용할때 오픈소스 API Gateway 가 서로 다르다. 
Zuul은 넷플릭스가 개발한 오픈소스 API 게이트웨이로, 주로 내부 서비스 간의 통신을 관리하는 데 사용된다. 
Spring Gateway는 외부 클라이언트와의 통신을 담당하는 API 게이트웨이로, 클라이언트의 요청을 적절한 서비스로 라우팅한다. 

Zuul: Internal Gateway

  • 넷플릭스가 개발한 오픈소스 API Gateway.
  • 주로 내부 서비스 간 통신을 관리.
  • 통일된 경로(path) 사용.
  • 서킷 브레이커: Hystrix
    • 스레드 풀 기반 관리.
    • 최소/최대 스레드 수 설정 가능.
    • 장애 확산 방지 기능 제공.
  • Servlet 기반 동작.
  • Blocking API 사용(요청/응답이 스레드에 의존).
  • Spring Cloud Gateway와 비교했을 때 상대적으로 개발 친화적이지 않음.

 

Spring Gateway: External Gateway

  • 외부 클라이언트와 통신을 담당.
  • 세부적인 경로(path) 설정 가능.
  • 서킷 브레이커: Resilience4j
    • 세마포어 기반 관리.
    • 스레드 수를 엄격히 제한하며 카운트로 처리.
    • Spring 3.0 이상에서 기본 제공.
  • 리액티브(Non-blocking) API 기반.
  • Spring WebFlux와 연동.
  • 경로 기반 라우팅, 필터 체인 구성 가능.
  • 보다 현대적인 설계와 Spring 생태계와의 강력한 통합

 

타임아웃 및 에러 처리

  • 타임아웃
    • 클라이언트 요청 시 전체 플로우 타임아웃
    • 클라이언트가 게이트웨이에 보낸 요청이 일정 시간 안에 응답을 받지 못하면 타임아웃이 발생
    • 게이트웨이와 API 구간 타임아웃(Ribbon, Feign 클라이언트).
    • 재시도 가능.
  • 에러 처리
    • 게이트웨이에서 처리 또는 서버에서 처리 가능.
    • 처리 위치에 따라 클라이언트-서버 간 데이터 흐름과 성능에 영향.

 

성능 최적화

  • API Gateway 타임아웃 설정으로 성능 개선.
    • API Gateway에서 적절한 타임아웃을 설정하면, 지연 시간이 긴 요청을 효율적으로 관리하여 시스템의 응답성을 높일 수 있다.
    • Amazon API Gateway는 응답 캐싱 및 페이로드 압축과 같은 최적화 전략을 제공하고 있다. 

간단히 예를 들면 Spring Cloud Gateway 에서 아래와 같이 작성할 수 있다. 아래 설정에서는 Gateway의 라우트에 대해 3초의 타임아웃을 적용한다. 클라이언트의 요청이 3초 안에 처리되지 않으면 타임아웃 예외가 발생하며, fallback URI로 요청이 전달하게 된다. 

spring:
  cloud:
    gateway:
      routes:
        - id: example-route
          uri: http://example-service
          predicates:
            - Path=/example/**
          filters:
            - name: RequestRateLimiter
            - name: CircuitBreaker
              args:
                fallbackUri: forward:/fallback
            - name: DedupeResponseHeader
          metadata:
            response-timeout: 3000  # 타임아웃 설정 (밀리초)
  • 서버 간 통신에서 서킷 브레이커 설정(Resilience4j 또는 Hystrix).

서킷 브레이커를 설정하게 되면 네트워크 지연, 서비스 장애 등으로 발생할 수 있는 성능저하를 방지할 수 있다. Resilience4j 예시를 들어보면 아래와 같다. 

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;

CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)   // 실패율 50% 이상 시 서킷 오픈
    .waitDurationInOpenState(Duration.ofSeconds(10))  // 서킷 오픈 후 대기 시간
    .slidingWindowSize(20)  // 슬라이딩 윈도우 크기
    .build();

CircuitBreaker circuitBreaker = CircuitBreaker.of("exampleService", config);
  • Spring 3.0 이상에서는 Resilience4j 권장.

 

Spring Cloud Gateway의 필터 사용 예제 

Spring Cloud Gateway는 필터 체인을 통해 요청과 응답을 조작할 수 있다. 

spring:
  cloud:
    gateway:
      routes:
        - id: example-route
          uri: http://example-service
          filters:
            - AddRequestHeader=Custom-Header, CustomValue
            - AddResponseHeader=Response-Header, ResponseValue
            - RewritePath=/oldpath/(?<segment>.*), /newpath/${segment}

 

Resilience4j의 Rate Limiter 사용 예제

Resilience4j는 서킷 브레이커 외에도 Rate Limiter를 제공한다.

RateLimiterConfig config = RateLimiterConfig.custom()
    .timeoutDuration(Duration.ofSeconds(1))
    .limitRefreshPeriod(Duration.ofSeconds(10))
    .limitForPeriod(5)
    .build();

RateLimiter rateLimiter = RateLimiter.of("exampleService", config);

 

결론

Gateway는 서킷 브레이커, 타임아웃, 에러 처리 기능을 통해 안정성과 성능을 높일 수 있다. MSA 환경에서 API Gateway는 단순한 요청 라우팅 도구를 넘어, 안정성과 확장성을 위한 핵심 역할을 수행한다. 

 

ref

https://blog.naver.com/PostView.nhn?blogId=hanajava&logNo=222459289490
https://github.com/spring-projects/spring-authorization-server/issues/564