MSA 구축 (9) - Feign Client 서버간 통신 하기

오형상·2024년 12월 13일
0

Ficket

목록 보기
9/27
post-thumbnail

마이크로서비스 아키텍처(MSA)는 각각 독립적으로 배포 및 운영될 수 있는 서비스로 구성됩니다. 그러나 이러한 독립성에도 불구하고, MSA 환경에서는 서비스 간에 통신이 필요한 경우가 빈번히 발생합니다. 이를 통해 각 서비스가 데이터를 공유하고 협력하여 사용자의 요구를 충족시킬 수 있습니다.

MSA 간의 통신은 크게 두 가지 방식으로 나뉩니다: 동기 방식비동기 방식입니다.


동기 방식

특징

  • 하나의 요청이 처리될 때까지 대기 상태를 유지하며, 즉각적인 응답을 요구합니다.
  • 일반적으로 HTTP 기반의 RESTful API를 통해 구현됩니다.
  • 동기 통신은 요청-응답 패턴이 명확하여 구현 및 디버깅이 용이하지만, 서비스 간의 강한 의존성을 초래할 수 있습니다.

구현 방법

  • RestTemplate: 스프링에서 제공하는 HTTP 통신을 위한 간단한 API 클라이언트.
  • FeignClient: 선언형 HTTP 클라이언트로, 코드 작성이 간결하고 유지보수성이 높습니다.

장점

  • 요청에 대한 즉각적인 응답을 받을 수 있습니다.
  • 구현이 간단하며 사용이 직관적입니다.

단점

  • 서비스 간 의존성이 강해질 수 있습니다.
  • 호출 대상 서비스가 느리거나 다운되면 전체 흐름이 지연될 가능성이 있습니다.
  • 네트워크 병목 현상이 발생할 수 있습니다.

비동기 방식

특징

  • 서비스 간의 시간적 독립성을 제공합니다.
  • 요청을 큐 또는 메시지 브로커에 전달하면, 요청자 서비스는 더 이상 관여하지 않습니다.
  • 일반적으로 AMQP, Kafka, RabbitMQ와 같은 메시지 큐를 통해 구현됩니다.

구현 방법

  • AMQP: Advanced Message Queuing Protocol을 사용하여 메시지를 전송하고 수신하는 방식.
  • Kafka/RabbitMQ: 분산 메시징 시스템을 활용한 이벤트 기반 아키텍처 설계.

장점

  • 확장성이 높고, 트래픽 부하를 완화할 수 있습니다.
  • 서비스 간의 의존성을 줄이고 독립성을 유지할 수 있습니다.

단점

  • 요청에 대한 응답을 즉시 확인할 수 없습니다.
  • 메시지 중복 처리 방지, 메시지 손실 처리 등 추가적인 관리 로직이 필요합니다.

FeignClient로 동기 통신 구현하기

FeignClient란?

FeignClient는 스프링 클라우드에서 제공하는 선언형 HTTP 클라이언트로, 동기 방식의 통신을 간결하고 효율적으로 구현할 수 있게 해줍니다. Feign을 사용하면 직접 RestTemplate 코드를 작성하지 않고, 인터페이스와 애노테이션만으로 HTTP 요청을 처리할 수 있습니다.

FeignClient의 주요 기능

  • 선언형 인터페이스 기반: HTTP 요청과 응답을 처리하는 인터페이스 정의.
  • 로드밸런싱 지원: Ribbon과 연계하여 클라이언트 측 로드밸런싱 가능.
  • 간단한 구현: 코드의 가독성과 유지보수성이 높음.

FeignClient 설정

  1. 의존성 추가
// Feign Client
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.0.2'
  1. FeignClient 활성화

FeignClient를 사용하려면 스프링 부트 애플리케이션에 @EnableFeignClients 애노테이션을 추가합니다.

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FicketUserApplication {

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

}
  1. FeignClient 인터페이스 정의
@FeignClient(name = "ticketing-service", fallbackFactory = TicketingServiceClientFallbackFactory.class)
public interface TicketingServiceClient {

    @GetMapping("/api/v1/ticketing/order/my")
    List<MyTicket> getMyTickets(@RequestParam Long userId);

}
  1. FeignClient 사용

FeignClient 인터페이스를 주입받아 서비스를 호출합니다.

@Slf4j
@Service
@Transcation
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;
    private final TicketingServiceClient ticketingServiceClient;


    /**
     * 마이 티켓 조회 서비스
     *
     * @param userId 사용자 ID
     * @return 마이 티켓 리스트
     */
    public List<MyTicket> getMyTicket(Long userId) {
        // 사용자 조회
        User user = userRepository.findByUserId(userId)
                .orElseThrow(() -> new BusinessException(ErrorCode.NOT_USER_FOUND));

        // Feign  Client를 사용하여 외부 서비스 호출
        List<MyTicket> ticketInfoDtoList = ticketingServiceClient.getMyTickets(user.getUserId())
        );
    }


  
    }
}
  1. 응답 모델 정의
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MyTicket{
    private Long orderId;
    private LocalDateTime createdAt;
    private LocalDateTime eventDateTime;
    private String eventStageName;
    private String sido;
    private String eventPcBannerUrl;
    private String eventMobileBannerUrl;
    private String eventName;
    private String companyName;
    private List<MySeatInfo> mySeatInfoList;
}
  1. 에러 핸들러 추가

FeignClient 호출 중 발생하는 에러를 처리하기 위해 ErrorDecoder를 설정합니다.

@Slf4j
@Component
public class FeignErrorDecoder implements ErrorDecoder {

    @Override
    public Exception decode(String methodKey, Response response) {
        log.error("Feign error occurred: status -> {} , methodKey -> {}", response.status(), methodKey);

        switch (response.status()) {
            case 400:
                return new IllegalArgumentException("Invalid request for user tickets.");
            case 404:
                return new NotFoundException("Tickets not found for the given user.");
            default:
                return new Exception("General Feign Error");
        }
    }
}

실행 결과

FeignClient를 통해 ticketing-service에서 사용자 티켓 정보를 가져오는 HTTP 요청이 간단히 처리됩니다. 오류가 발생할 경우 설정된 ErrorDecoder가 동작하여 적절한 예외를 던집니다.


지금까지 FeignClient를 활용한 동기 방식의 마이크로서비스 통신 구현을 살펴보았습니다.

장애 상황에서 CircuitBreaker를 사용하면 특정 서비스가 일시적으로 문제가 있을 때 자동으로 대체 경로를 제공하거나 요청을 차단하여 시스템 전체의 안정성을 유지할 수 있습니다. 다음 단계에서는 이를 활용한 구현 방법을 다뤄보겠습니다.

0개의 댓글