컴퓨터 프로그래밍/CS

Feign Client 를 만든 Netflix

한33 2025. 4. 7. 17:29

✔️ Feign Client 란?

Feign Client 는 HTTP 요청을 인터페이스만으로 처리를 할 수 있게 도와주는 클라이언트이다.Spring Cloud 에서 제공하는 @FeignClient 어노테이션을 이용해서 메서드 호출처럼 외부 API 나 다른 마이크로서비스를 쉽게 호출할 수 있게 한다.

 

✔️ 넷플릭스는 왜 Feign Client 를 만들었을까?

넷플릭스는 전 세계 수억 명에게 서비스를 제공하면서, 초대형 마이크로서비스 아키텍처로 전환했다.서비스 간의 수많은 HTTP 통신을 안정적이고 효율적으로 처리해야 했고, 이 과정에서 문제들을 겪는다.

 

 

  • HTTP 요청 코드가 너무 많고 반복적이다.
  • 실패 처리(fallback)나 로드밸런싱을 일일이 다 구현해야 한다.
  • 코드가 복잡해서 유지보수가 힘들다.

그래서 간결하고 선언적인 HTTP 클라이언트인 Feign 을 만들었다.

 

✔️ Feign Client 를 왜 사용할까?

1. 간결한 코드

  • RestTemplate 나 WebClient 보다 코드가 훨씬 짧고 선언적으로 작성이 가능하다.
  • 비즈니스 로직에 집중할 수 있다.

 

2. 마이크로 서비스 간 통신 최적화

  • 여러 서비스가 서로 HTTP로 통신해야 할 때, Feign 은 이를 쉽게 해준다.
  • 서비스 이름만 넣으면 Ribbon 으로 로드 밸런싱까지 가능하다.

 

3. Spring Cloud 와의 통합

  • Eureka, Ribbon, Hystrix (중단)  등과 쉽게 연동이 가능하다.
  • 장애가 생기면 fallback 처리도 가능하다.

 

4. 유지보수가 쉬움

  • 인터페이스만 보면 어떤 API 를 호출하는지 바로 알 수 있다.
  • 변경도 간단하고 테스트하기도 편리하다.

 

✔️ 어떻게 사용할까?

상황 : 필자는 메인서버와 알림서버를 분리했고 이 과정에서 Header 에 JWT 토큰을 담아 알림서버에 SSE 구독을 요청하면, 알림서버에서 Feign Client 를 사용해 메인서버로 부터 JWT 인증을 요구. 이후 userId 를 받아오는 로직을 작성했다.

 

Main Server

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/v1/api/internal/users")
public class InternalUserController {

    @GetMapping("/me")
    public ResponseEntity<UserInfoResponseDto> getMyInfo(@AuthenticationPrincipal
                                                          AuthUser authUser) {
        log.info("FeignClient 작동 "+ authUser.getUserId());
        return ResponseEntity.ok(new UserInfoResponseDto(authUser.getUserId()));
    }
}

 

 

메인서버에서 알림서버로 부터 호출받을 api 엔드포인트를 지정해주었다.

확인을 위해 log 를 찍었고, UserInfoResponseDto 라는 단순 id 값을 반환하는 dto 를 만들어주었다.

JWT 토큰이 들어오면 해당 토큰으로부터 userId 값을 반환시킨다.

 

Notification Server

build.gradle

// Feign
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
dependencyManagement {
    imports {
       mavenBom "org.springframework.cloud:spring-cloud-dependencies:2023.0.1"
    }

 

 

위처럼 의존성을 추가해준다.

 

UserClient

@FeignClient(name = "userClient", url = "${user-service.url}", configuration = FeignClientConfig.class)
public interface UserClient {
    @GetMapping("/v1/api/internal/users/me")
    UserInfoResponseDto getMyInfo();
}

 

@FeignClient 어노테이션을 활용해서 메인 서버에 지정한 api 로 연결을 시키는 getMyInfo 메서드를 만들어준다.

 

NotificationApplication

@SpringBootApplication
@EnableJpaAuditing
@EnableFeignClients(basePackages = "com.sparta.notification.domain.notifications.client")
public class NotificationApplication {

    public static void main(String[] args) {
       SpringApplication.run(NotificationApplication.class, args);
    }

}

 

@EnableFeignClients 어노테이션을 Application Main 파일에 붙여준다.

 

Long userId = userClient.getMyInfo().getUserId();

 

이후 이렇게 메서드를 사용하듯이 getMyInfo 메서드를 호출해주면 

 

메인서버에서 위 로그와 같이 api 가 호출된 것을 확인할 수 있다.