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