본문 바로가기

Spring/Spring Cloud

Zuul - API Gateway

반응형

API Gateway 란,

  • 클라이언트와 백엔드 서버 사이의 출입문
  • 특정 URL 요청에 대한 라우팅 ( 라우팅, 필터링, API 변환, 클라이언트 어댑터 API, 서비스 프록시 )
  • 횡단 관심사 cross-service concerns ( => 모든 애플리케이션이 가지고 있는 관심사. 그러나, 중복적이고 복잡한.. )
    • 보안 - 인증 ( authentication ), 인가 ( authorization )
    • 일정량 이상의 요청 제한 ( rate limiting )
    • 계측 ( metering ) => API 호출에 대한 통계
    • 로깅
    • 프록시

 

Zuul 이란,

  • 마이크로 프록시
  • 실제 넷플릭스에서는 50개 이상의 AWS ELB 의 앞단에 위피해 3개의 AWS 리전에 걸펴 하루 백억 이상의 요청을 처리하고 있다고 한다.
  • 멀티 리전 중 하나의 리전에서 장애가 났을 때, zuul을 통해 다른 리전으로 프록시하는 역활을 함zuul 의 모든 API 요청은 HystrixCommand 로 구성되어 전달된다.
    • 각 API 경로 (서버군) 별로 Circuit Breaker 를 생성
    • 하나의 서버 군이 장애를 일으켜도 다른 서버 군의 서비스에는 영향이 없다.
    • CircuitBreaker / ThreadPool 의 다양한 속성을 통해 서비스 별 속성에 맞는 설정 가능

  1. API를 전달할 서버의 목록을 갖고 내장되어있는 Ribbon 을 통해 Load-Balancing 을 수행한다.
    • 주어진 서버 목록들을 라운드 로빈 방식으로 호출
    • Coding 을 통해 로드 밸런싱 방식을 커스터마이징 하는 것이 가능하 다.
  2. Eureka Client를 사용하여 주어진 URL 의 호출을 전달할 '서버 리스트'를 찾는다
    • Zuul에는 Eureka Client 가 내장되어 있어 각 URL 에 Mapping 된 서비스 명을 찾아서 Eureka Server 를 통해 목록을 조회 한다.
    • 조회된 서버 목록을 'Ribbon' 클라이언트에게 전달한다.
  3. Eureka + Ribbon에 의해서 결정된 Server 주소로 Http 요청
    • Apache Http Client 가 기본
    • OK Http Client 사용 가능
  4. 선택된 첫 서버로의 호출이 실패할 경우 Ribbon에 의해서 자동으로 Retry 수행
    • Retry 수행 조건
      • http Client 에서 Exception 발생 (IOException)
      • 설정된 HTTP 응답 코드 반환 ( ex 503 )

Zuul의 모든 호출은 

  • HystrixCommand 로 실행되므로 Circuit Breaker 를 통해 
    • 장애시 Fail Fask 및 Fallback 수행 가능
  • Ribbon + Eureka 조합을 통해
    • 현재 서비스가 가능한 서버의 목록을 자동으로 수신
  • Ribbon의 Retry 기능을 통해
    • 동일한 종류의 서버들로의 자동 재시도가 가능

Zuul

Build.gradle

dependency 추가

    compile('org.springframework.cloud:spring-cloud-starter-netflix-zuul')

application.yml

routes 부분에 API 라우팅 룰에 대해 설정한다. ( path, service id, 등.. )

eureka 부분에 유레카 서버에 대한 정의를 해준다.

 
server:
  port: 8765

zuul:
  routes:
    product:
      path: /products/**
      serviceId: product
      stripPrefix: false
    display:
      path: /displays/**
      serviceId: display
      stripPrefix: false

eureka:
  instance:
    non-secure-port: ${server.port}
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

 

zuul (8765) 로 요청을 했으나, 해당 서비스 아이디를 통해 유레카에 등록된 서버 ip / port 와 URL path 를 이용해 그대로 프록시 되고, 그 결과가 반환된다.

그리고 각 요청은 HystrixCommand에 감싸져 있고, 각 요청은 Ribbon을 통해 유레카의 서버 목록에 대해 라운드 로빈을 통해 호출이 되게 된다.

이에 Spring Cloud 가 제공하는 많은 기능을 사용할 수 있도록 하기 위해 Spring Cloud Zuul이 등장

기본 isolation 은 SEMAPHORE 이다. (Netflix Zuul의 기본 격리 단위는 스레드 풀)
=> 서블릿 스레드 갯수와 관계없이, 세마포어의 개수에 따라 커넥션 가능한 수가 결정된다. ( 그 이상의 호출은 fallback... )
=> 하지만, SEMAPHORE
 는 네트워크 타임아웃을 격리시켜주지 못한다.
=> 인터럽트 요청이 왔을 때, 스레드를 종료시킬지, 인터럽트를 수행할 지 결정하는 것은 스레드 자체가 하는데, 세마포어로는 스레드의 인터럽트를 제어하지 못한다.
=> 스레드를 생성하는 비용이 없기 때문에 성능 상으로는 세마포어가 이점이 있지만, 이러한 한계가 있기 때문에 격리 단위를 세마포어가 아닌 스레드 풀로 변경해서 사용하기도 한다.
=> 기본적으로는, 스프링 zuul에서는 모든 서비스에 대해 ( RibbonCommand라는 이름으로 ) 단 하나의 스레드 풀이 생성되게 된어 서비스에 대한 HystrixCommand 를 하나의 스레드 풀에서 생성하게 된다.
=> use-separate-thread-pools과 thread-pool-key-prefix 옵션을 통해 Thread 를 서비스 별로 격리할 수 있도록 기능을 제공해준다.

 
server:
  port: 8765

zuul:
  routes:
    product:
      path: /products/**
      serviceId: product
      stripPrefix: false
    display:
      path: /displays/**
      serviceId: display
      stripPrefix: false
  ribbon-isolation-strategy: thread
  thread-pool:
    use-separate-thread-pools: true
    thread-pool-key-prefix: zuul-

eureka:
  instance:
    non-secure-port: ${server.port}
    prefer-ip-address: true
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 1000
    product:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 10000
  threadpool:
    zuul-product:
      coreSize: 30
      maximumSize: 100
      allowMaximumSizeToDivergeFromCoreSize: true
    zuul-display:
      coreSize: 30
      maximumSize: 100
      allowMaximumSizeToDivergeFromCoreSize: true

 

참조 > Spring Cloud 기반 MSA로의 전환

반응형

'Spring > Spring Cloud' 카테고리의 다른 글

Feign  (0) 2021.01.17
Eureka  (0) 2021.01.17
Hystrix & Ribbon  (0) 2021.01.17