Spring Cloud OpenFeign으로 API 호출해보기

개발자·2022년 9월 7일
1

MSA

목록 보기
6/7
post-thumbnail

Spring Cloud OpenFeign

Netflix에서 만든 HTTP client binder로 웹 서비스 client를 쉽게 작성할 수 있게 해준다.
RestTemplate 대체로 사용할 수 있으며, Spring Cloud 프로젝트에서 매핑해서 제공한다. 인터페이스를 작성하고 Annotation을 선언해 편리하게 구현할 수 있다. Feign을 사용하면 MSA에서 많은 API 호출을 위해 복잡한 소스코드를 일일이 작성해야하는 단점을 해결할 수 있다.

- RestTemplate vs Feign

RestTemplate는 시간이 지날수록 유지보수하기 어렵다. 불필요한 코드를 반복적으로 작성해야 하며, 테스트하기도 쉽지 않다. 반면, Feign은 인터페이스를 작성하고 Annotation을 선언하기만 하면 되기 때문에 매우 심플하다. 테스트도 간편하기 때문에 RestTemplate에 비해서 클라이언트 코드를 보다 쉽게 작성할 수 있다.

사용 방법

FeignClient

  1. openfeign dependency를 추가한다.
    나는 maven을 사용중이므로 pom.xml에 dependency를 추가해줬다.
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
	<version>3.0.4</version>
</dependency>
  1. application.yml 설정을 추가해준다.
    Feign log는 DEBUG 레벨에서만 동작하므로 logger-level: FULL로 변경해주었다. 이 외에도 timeout 같은 속성들을 설정해줄 수 있다.
feign:
  client:
    config:
      default:
        logger-level: FULL
#        connect-timeout: 1
#        read-timeout: 1
  httpclient:
    enabled: true
  1. root package에 @EnableFeignClients 를 선언한다.(또는 basePackages를 지정해준다.)
    이렇게 해야 package 내부의 @FeignClient를 찾아 구현체를 만들어준다.
@SpringBootApplication
@EnableFeignClients
public class TaskUserServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(TaskUserServerApplication.class, args);
  }
}
  1. FeignClient 인터페이스를 작성해준다.
    Eureka를 사용중이라면 @FeignClient의 name에 Eureka에 등록한 Application name을 입력해주면 된다. value에는 호출할 API의 url을 입력해준다. 이 외에도 configuration, fallback 등을 지정해줄 수 있다.
    (참고: 메서드의 DTO에 아무것도 작성하지 않으면 @RequestBody로 인식한다.)
@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로 바꾸니 해결되었다.
왜 그런지 아시는 분은 댓글 부탁드립니다..😭😢

  1. 서비스 단에서 API 호출 코드를 추가해준다.
    생성자 주입 방식으로 TaskFeignClient 의존관계를 주입해준 후 위에서 작성한 API를 호출한다.
private final UserFeignClient userFeignClient;

@Transactional
public void deleteTask(DeleteTaskRequest request) throws Exception {
    userFeignClient.deleteTask(request.getTaskId(), request);
}

이렇게 다른 서비스의 API를 호출하는 경우 호출한 서비스에 문제가 생기면 문제가 전파될 수 있다. 이런 경우를 대비하기 위해 Circuit Breaker를 사용해보자.

Circuit Breaker

Circuit Breaker란 회로 차단기라는 뜻으로 MSA 아키텍처에서 한 서비스에 장애가 발생했을 때 차단해, 다른 서비스에 장애가 전파되는 것을 방지해준다.

OpenFeign이 HystrixFeign라는 Hystrix 기반 Circuit Breaker를 지원하고 있기 때문에 Hystrix를 사용해보자!
참고로 hytrix는 유지관리 모드로 더 이상 개발되지 않으므로 Resilience4j가 대안으로 권장되고 있다. OpenFeign은 Resilience4J와 Spring Circuit Breaker도 지원할 예정이라고 한다.(장기 목표)

Hystrix

Hystrix는 분산환경을 위한 장애 및 지연 내성을 갖도록 도와주는 라이브러리로써, Circuit Breaker Pattern을 적용하여 MSA 애플리케이션의 장애 전파를 방지할 수 있다.


사용 방법

  1. application.yml에 아래 속성을 추가해준다.
feign:
  hystrix:
    enabled: true

#Spring-Cloud 2020.0.x 버전은 아래 설정을 사용한다.
feign:
  circuitbreaker:
    enabled: true

나는 Spring-cloud 2020.0.4를 사용중이라 위 설정으로 했을때 잘 안돼서 아래 설정을 사용했다. -> 참고한 링크

  1. 장애 발생시 실행될 fallback을 정의해준다.

    Fallback
    - 실행을 실패(Exception)하는 경우에 대신 실행되게하는 프로세스

public class UserFeignClientFallback implements UserFeignClient{
	@Override
	public void deleteTask(String taskId, DeleteTaskRequest request) {
    	log.debug("TaskService Error fallback");
	}
}
  1. fallback의 원인에 접근하고 싶다면 fallbackFactory를 사용할 수 있다.
@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());
      }
    };
  }
}
  1. FeignClient에 fallbackFactory 속성을 추가해준다.
    fallback을 추가할 경우엔 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);
}
  1. 강제로 Exception을 발생시켰을 때 fallbackFactory가 실행되는 것을 확인할 수 있다.

마무리

이렇게 Spring Cloud OpenFeign과 Hystrix를 사용해 보았다.
위에 작성한 내용 이외에도 Configuration 설정이나 SpringQueryMap 등 유용한 기능이 많으니 공식 문서들을 참고해보시길 🤗🤭😚



Ref.

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

profile
log.info("공부 기록 블로9")

0개의 댓글