Netflix에서 만든 HTTP client binder로 웹 서비스 client를 쉽게 작성할 수 있게 해준다.
RestTemplate 대체로 사용할 수 있으며, Spring Cloud 프로젝트에서 매핑해서 제공한다. 인터페이스를 작성하고 Annotation을 선언해 편리하게 구현할 수 있다. Feign을 사용하면 MSA에서 많은 API 호출을 위해 복잡한 소스코드를 일일이 작성해야하는 단점을 해결할 수 있다.
RestTemplate는 시간이 지날수록 유지보수하기 어렵다. 불필요한 코드를 반복적으로 작성해야 하며, 테스트하기도 쉽지 않다. 반면, Feign은 인터페이스를 작성하고 Annotation을 선언하기만 하면 되기 때문에 매우 심플하다. 테스트도 간편하기 때문에 RestTemplate에 비해서 클라이언트 코드를 보다 쉽게 작성할 수 있다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>3.0.4</version>
</dependency>
application.yml
설정을 추가해준다.logger-level: FULL
로 변경해주었다. 이 외에도 timeout 같은 속성들을 설정해줄 수 있다.feign:
client:
config:
default:
logger-level: FULL
# connect-timeout: 1
# read-timeout: 1
httpclient:
enabled: true
@EnableFeignClients
를 선언한다.(또는 basePackages를 지정해준다.)@FeignClient
를 찾아 구현체를 만들어준다.@SpringBootApplication
@EnableFeignClients
public class TaskUserServerApplication {
public static void main(String[] args) {
SpringApplication.run(TaskUserServerApplication.class, args);
}
}
@FeignClient
의 name에 Eureka에 등록한 Application name을 입력해주면 된다. value에는 호출할 API의 url을 입력해준다. 이 외에도 configuration, fallback 등을 지정해줄 수 있다.@FeignClient(name = "taskmng-task")
public interface UserFeignClient {
@PostMapping(value = "/tasks/{taskId}", consumes = "application/x-www-form-urlencoded")
void deleteTask(@PathVariable String taskId, DeleteTaskRequest request);
}
++ 추가로 나는 Consume으로 Http Body의 데이터 타입을 명시해주었다. 왜 그런진 모르겠지만 application/json
으로 명시해주니 호출 받는 쪽에서 json->DTO 매핑을 못해줘 null 값이 들어왔다. 그래서 application/x-www-form-urlencoded
로 바꾸니 해결되었다.
왜 그런지 아시는 분은 댓글 부탁드립니다..😭😢
private final UserFeignClient userFeignClient;
@Transactional
public void deleteTask(DeleteTaskRequest request) throws Exception {
userFeignClient.deleteTask(request.getTaskId(), request);
}
이렇게 다른 서비스의 API를 호출하는 경우 호출한 서비스에 문제가 생기면 문제가 전파될 수 있다. 이런 경우를 대비하기 위해 Circuit Breaker를 사용해보자.
Circuit Breaker란 회로 차단기라는 뜻으로 MSA 아키텍처에서 한 서비스에 장애가 발생했을 때 차단해, 다른 서비스에 장애가 전파되는 것을 방지해준다.
OpenFeign이 HystrixFeign라는 Hystrix 기반 Circuit Breaker를 지원하고 있기 때문에 Hystrix를 사용해보자!
참고로 hytrix는 유지관리 모드로 더 이상 개발되지 않으므로 Resilience4j가 대안으로 권장되고 있다. OpenFeign은 Resilience4J와 Spring Circuit Breaker도 지원할 예정이라고 한다.(장기 목표)
Hystrix는 분산환경을 위한 장애 및 지연 내성을 갖도록 도와주는 라이브러리로써, Circuit Breaker Pattern을 적용하여 MSA 애플리케이션의 장애 전파를 방지할 수 있다.
application.yml
에 아래 속성을 추가해준다.feign:
hystrix:
enabled: true
#Spring-Cloud 2020.0.x 버전은 아래 설정을 사용한다.
feign:
circuitbreaker:
enabled: true
나는 Spring-cloud 2020.0.4를 사용중이라 위 설정으로 했을때 잘 안돼서 아래 설정을 사용했다. -> 참고한 링크
Fallback
- 실행을 실패(Exception)하는 경우에 대신 실행되게하는 프로세스
public class UserFeignClientFallback implements UserFeignClient{
@Override
public void deleteTask(String taskId, DeleteTaskRequest request) {
log.debug("TaskService Error fallback");
}
}
@Slf4j
@Component
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient>{
@Override
public UserFeignClient create(Throwable cause) {
return new UserFeignClient() {
@Override
public void deleteTask(String taskId, DeleteTaskRequest request) {
log.debug("★ Fallback reason was: " + cause.getMessage());
}
};
}
}
fallback = 클래스명.class
로 정의해주면 된다.@FeignClient(name = "taskmng-task", fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {
@PostMapping(value = "/tasks/{taskId}", consumes = "application/x-www-form-urlencoded")
void deleteTask(@PathVariable String taskId, DeleteTaskRequest request);
}
이렇게 Spring Cloud OpenFeign과 Hystrix를 사용해 보았다.
위에 작성한 내용 이외에도 Configuration 설정이나 SpringQueryMap 등 유용한 기능이 많으니 공식 문서들을 참고해보시길 🤗🤭😚
https://github.com/OpenFeign/feign
https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html
https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/#spring-cloud-feign-circuitbreaker-fallback
https://techblog.woowahan.com/2657/
https://sabarada.tistory.com/118
https://velog.io/@wodyd202/Hystrix-%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80