Feign
- REST 기반 서비스 호출을 추상화한 Spring Cloud Netflix 라이브러리
- 선언적 방식
- 인터페이스를 통해 클라이언트 측 프로그램 작성
- Spring이 런타임에 구현체를 제공
Dependencies
1 | dependencyManagement { |
Example
@EnableFeignClients
1 |
|
interface 정의
1 | "post-api", url = "${feign.post-api.url}") (name = |
사용
1 |
|
Feign 설정
@FeignClient
- name : 서비스ID 혹은 논리적인 이름, spring-cloud의 eureka, ribbon에 사용
- url : 실제 호출할 서비스의 URL, eureka, ribbon을 사용하지 않고서도 동작
- decode404 : 404응답이 올 때
FeignExeption
을 발생시킬지, 아니면 응답을 decode할 지 여부 - configuration : feign configuration class 지정
- fallback : hystrix fallback class 지정
- fallbackFactory : hystrix fallbak factory 지정
Hystrix란?
spring-cloud
의 서비스 중 하나. Circuit Breaker Pattern을 사용. 뒷단 API 서버가 장애 발생 등의 이유로 일정 시간(Time window) 내에 여러번 오류 응답을 주는 경우(timeout, bad gateway 등), 해당 API 서버로 요청을 보내지 않고 잠시 동안 대체(fallback) method를 실행. 일정 시간이 지나서 다시 뒷단 API 서버를 호출하는 등의, 일련의 작업을 제공해준다. Circuit Breaker Pattern(마틴 파울러)
application.yml 설정
.properties
로 하면 장황해질 것 같아, yml
로 설명
아래 설정은 @FeignClient(configuration = FooConfiguration.class)
으로 선언할 수 있음
1 | feign: |
- connectionTimeout, readTimeout : hystrix의 timeout 설정이 더 짧으면, hystirx 옵션을 따라감
- loggerLevel : NONE, BASIC, HEADER, FULL을 지정할 수 있음
- NONE : default, 로그를 남기지 않음
- BASIC : Request Method, URL과 응답 코드, 실행 시간을 남김
- HEADERS :
BASIC
의 정보를 포함하여, 요청, 응답의 헤더를 남김 - FULL : 요청, 응답의 header, body, metadata를 남김
logging.level.com.example.demo.PostClient: debug
등의 debug logger 설정이 되어 있어야함
- encoder, decode : body의 내용을 Object로 변경하는 class 지정, 각각
- retryer : 요청이 실패했을 때 재시도에 대한 정책
java설정
1 |
|
@FeignClient(configuration = FooConfiguration.class)
와application.yml
이 같이 있을 시에는,yml
설정이 우선. 우선 순위를 변경하고 싶으면feign.client.default-to-properties: false
를yml
에 설정
java설정(spring 연동 없는 순수 open feign 설정)
1 | public interface PostClient { |
Feign Hystrix Support
classpath 내에 hystrix가 있으며, feign.hystrix.enabled: true
설정이 되었다면 Hystrix를 사용 가능
1 | compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix') |
Hystrix를 사용하는 경우 기본적으로 thread time out이 1초
때문에 기본 설정으로는 feign의 connection, read timeout이 1초 이상인 경우라도
1초 안에 응답이 오지 않으면 fallback이 실행되므로 주의
1 | feign: |
Fallback
1 | // Feign 선언 |
http://localhost:8080/delay/1
성공
1 | { |
1 | DEBUG 60528 --- [-http-bin-api-1] c.p.s.httpbin.client.HttpBinClient : [HttpBinClient#delay] ---> GET https://httpbin.org/delay/1 HTTP/1.1 |
http://localhost:8080/delay/5
timeout!!!
1 | {"origin":null, "url":null} |
1 | DEBUG 60528 --- [-http-bin-api-5] c.p.s.httpbin.client.HttpBinClient : [HttpBinClient#delay] ---> GET https://httpbin.org/delay/5 HTTP/1.1 |
회로 열림 상태(Circuit Open) - Hystrix에 대해서
위 예제에 대해서 Hystrix의 동작을 아래와 같이 튜닝
1 | hystrix: |
execution.isolation.thread.timeoutInMilliseconds
: hystirx명령에 대해 3초 timeout 설정metrics.rollingStats.timeInMilliseconds
: 60초의 window slice를 가짐(30초씩 감시)circuitBreaker.requestVolumeThreshold
: 최소 5번 이상의 요청이 있어야함circuitBreaker.errorThresholdPercentage
: 50% 이상 오류가 발생시 회로를 오픈(circuit open)- 즉 최근 1분 내에, 5번 이상의 요청이 있었고, 그 중 50% 이상이 오류가 발생했다면, command를 실행하지 않고 fallback을 실행하겠다는 의미임
- 회로가 열린 후, 일정시간(
circuitBreaker.sleepWindowInMilliseconds
)동안 fallback 응답을 보내고 성공하면 회로를 닫음
timeout이 5번 이상 발생시 로그
1 | 2018-02-28 15:46:37.653 DEBUG 99893 --- [-http-bin-api-1] c.p.s.httpbin.client.HttpBinClient : [HttpBinClient#delay] ---> GET https://httpbin.org/delay/5 HTTP/1.1 |
https://httpbin.org/delay/5
에서 5번 실패가 발생한 이후에는 바로 fallback을 호출
Fallback Factory
앞서 살펴보았던 Fallback은 어떤 Exception이 발생했는지 알 수가 없음
1 | "http-bin-api", url = "${feign.http-bin-api.url}", fallbackFactory = HttpBinClientFallbackFactory.class) (name = |
오류 발생시 로그
1 | 2018-02-28 16:03:26.213 ERROR 14890 --- [ HystrixTimer-1] c.p.s.h.c.HttpBinClientFallbackFactory : null |
fallbackFactory를 사용할 때에, Spring Application이 올라오면서 검증차원에서 일부러 fallbackFactory를 한 번 실행시킴.
Object exampleFallback = fallbackFactory.create(new RuntimeException());
때문에 불필요한 log가 올라오는데, 이를 배제할 방법을 모름…
Feign 상속 지원
Feign이 Spring MVC의 @Controller
의 애너테이션들을 사용하는 것을 응용해서 다음과 같은 소스를 작성할 수 있음
1 | public interface UserService { |
이처럼 다른 곳에 API client를 납품할 일이 있을때, Feign을 사용한다면UserService
를 serivce
모듈에 넣고, 그를 구현한 UserController
를 api
모듈에 넣고,
그에 대한 feign client인 UserClient
를 client
모듈에 넣어client
모듈을 외부에 공유하는 식의 개발도 가능
하지만 권장하지 않음. server-client 간의 커플링을 높이며, 현재 실질적으로 Spring MVC의 기능을 Feign이 모두 소화하고 있지 않음
요청, 응답 압축
GZIP을 통해 요청, 응답을 압축
1 | feign: |
Pageable
spring-data
를 쓰는 환경이라면 Pageable
을 빼놓을 수 없음
아쉽게도 요청이나, 응답을 받을 때 Pageable
이나 Page<T>
를 지원하지는 않음
직접 Encoder와 Jackson 설정을 해야함
Pageable 요청 보내기
아래와 같이 Encoder를 구현하여, Pageable로 요청을 만들 수 있음
참고 : https://github.com/spring-cloud/spring-cloud-netflix/issues/556
1 |
|
Encoder
로 할 수 있는 일이 한정적이기 때문에, 실제 운영에서 사용하고자 않다면 아래와 같은 구현체를 만들어야함
1 |
|
Page 응답 Json 파싱하기
Jackson 설정
참고 : https://github.com/spring-cloud/spring-cloud-netflix/issues/556
1 |
|