본문 바로가기
DDD&MSA

[MSA] Feign Client - 마이크로 서비스 간 통신 구현하기

by 덩라 2023. 11. 8.

본 포스팅은 MSA 공부 간 작성한 포스팅 입니다.

아래 포스팅을 먼저 보고 오시면 이해에 도움이 되시니 참고 부탁드립니다.

https://byunsw4.tistory.com/35

 

[MSA] API Gateway 에 인증 구현하기 - GatewayFilter 추가하기

본 포스팅은 MSA 공부 간 작성한 포스팅 입니다. 아래 포스팅을 먼저 보고 오시면 이해에 도움이 되시니 참고 부탁드립니다. https://byunsw4.tistory.com/34 [MSA] API Gateway - 마이크로 서비스 Routing 처리하

byunsw4.tistory.com

 

본 포스팅에서 제시된 예시 코드는 아래 github 에서 확인하실 수 있습니다.

https://github.com/dongha-byun/springboot-shoppingmall

https://github.com/dongha-byun/springboot-shoppingmall-user-micro-service


1. 마이크로 서비스 간 통신

MSA 구성 내에서 마이크로 서비스 간의 통신이 필요한 경우가 있습니다.

예를 들면, 온라인 쇼핑몰을 운영하는 판매업체에서 "특정 회원등급 이상의 회원에게 쿠폰을 발급한다." 라는 요구사항이 있는 경우, 쿠폰 발급을 위한 "특정 회원등급 이상의 회원 정보" 가 필요할 것 입니다.

이 경우, 쿠폰 발급을 위한 서비스와 회원정보를 담당하는 서비스가 마이크로 서비스로 분리되어 있다면, 아래와 같은 구조를 가지게 될 것 입니다.

 

위 흐름을 봤을 때, 3. 발급 대상 조회 요청 을 통해 사용자 마이크로 서비스는 특정 회원등급 이상의 회원 목록을 검색 후, 쿠폰 마이크로 서비스에게 응답하도록 되어 있습니다.

각각의 마이크로 서비스가 서로 독립적인 웹 서비스 인 점을 봤을 때, RestTemplate 를 사용하여 통신하면 되는데 MSA 로 이루어진 구조의 경우, Spring Cloud OpenFeign FeignClient 기능을 통해 쉽게 구현할 수 있습니다.

Open Feign 을 사용하여 마이크로 서비스 간 통신을 구현하는 경우, 각각의 마이크로 서비스가 모두 유레카 서버(디스커버리 서비스)에 등록되어 있으면, 등록된 애플리케이션의 이름 만으로도 마이크로 서비스 간 통신을 구현할 수 있습니다.
본 포스팅에선 모든 마이크로 서비스를 유레카 서버에 등록했다고 가정하고 설명합니다.

 

2. Spring Cloud OpenFeign 으로 구현해보기

우선, 사용자 마이크로 서비스에서 제공해야하는 API 가 다음과 같다고 가정해보겠습니다.

@RestController
public class UserMicroServiceController {

    private final UserQueryDAO userQueryDAO;

    public UserMicroServiceController(UserQueryDAO userQueryDAO) {
        this.userQueryDAO = userQueryDAO;
    }

    @GetMapping("/users/above-grade")
    public ResponseEntity<List<Long>> getUserIdsAboveGrade(@RequestParam("targetGrade") String targetGrade) {
        UserGrade userGrade = UserGrade.valueOf(targetGrade);
        List<Long> userIdsAboveGrade = userQueryDAO.getUserIdsAboveGrade(userGrade);

        return ResponseEntity.ok().body(userIdsAboveGrade);
    }
}

 

본 API 는 GET /users/above-grade?targetGrade={grade} 요청을 받아, 대상 사용자들의 id 목록을 응답하는 API 입니다.

 

위 API 를 호출할 쿠폰 마이크로 서비스 측에 사용자 마이크로 서비스에 요청을 보내기 위한 코드를 Spring Cloud OpenFeign 을 통해 작성해보고자 합니다.

 

우선, Open Feign 을 사용하기 위해 쿠폰 마이크로 서비스가 속한 프로젝트에 Spring Cloud OpenFeign의 의존성을 추가해줍니다.

```build.gradle

dependencies {
	// == 중략 == //
    
	// spring eureka client
	implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
	implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'

}

 

eureka client 등록을 위한 spring-cloud-starter-netflix-eureka-client 의존성 과 openfeign 사용을 위한 spring-cloud-starter-openfeign 의존성을 추가해줍니다.

 

그리고, 해당 프로젝트에서 OpenFeign 을 통해 FeignClient 를 사용하겠다는 의미로 main class 에 아래와 같이

@EnableFeignClients annotation 을 추가합니다.

// @EnableFeignClients : 본 프로젝트에서 FeignClient 를 사용한다는 뜻
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class ShoppingMallApplication {

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

}

 

여기까지하면 FeignClient를 사용할 준비가 완료되었습니다.

 

이제 직접적으로 사용자 마이크로 서비스에게 요청을 보내 응답을 얻을 FeignClient 객체를 생성해보겠습니다.

FeignClient 는 interface 기반으로 구현되며, 애플리케이션 실행 시 Spring Cloud 내부에서 구현체를 생성해줍니다.

이로 인해, 개발자는 개발과정에서 직접 구현체를 개발할 필요가 없고, OpenFeign 의외의 별다른 기술에 의존할 필요가 없습니다.

(개발자가 직접 RestTemplate 과 같은 Http 통신을 위한 기술을 구현할 필요가 없음)

 

아래는 사용자 마이크로 서비스와의 통신을 위한 FeignClient 의 구현코드 입니다.

import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(name = "user-service")
public interface UserServiceClient {

    @GetMapping(value = "/users/above-grade")
    List<Long> getUserIdsAboveTheGrade(@RequestParam("targetGrade") String targetGrade);

}

 

@FeignClient annotation 을 interface 에 붙여줌으로써, 해당 interface 가 마이크로 서비스 통신을 위한 FeignClient 임을 명시해주고, name 속성에는 해당 FeignClient 가 요청을 보내고자 하는 마이크로 서비스의 application name 을 명시해줍니다.

포스팅 초반에 가정한대로, 사용자 마이크로 서비스와 쿠폰 마이크로 서비스 둘 다 유레카 서버에 등록되어 있기 때문에 name 만으로도 마이크로 서비스 간 통신이 가능합니다.

 

그 후, interface 에 메서드를 RestController 의 API 를 개발하는 방식과 동일하게 개발해주면 됩니다.

FeignClient 에 개발되는 @GetMapping("/users/above-grade") 와 @RequestParam("targetGrade") 등의 API 정보들은 앞서 개발한 사용자 마이크로 서비스에 개발된 API 와 동일해야 된다는 점을 주의해야 합니다.

 

이렇게 개발된 FiegnClient 를 실제 쿠폰 마이크로 서비스의 로직에서 사용해보면, 아래와 같이 사용되게 됩니다.

@RequiredArgsConstructor
@Transactional
@Service
public class CouponService {
    private final CouponRepository couponRepository;
    
    // FeignClient 로 구현된 객체
    private final UserServiceClient userServiceClient;

    public Long create(CouponCreateDto couponCreateDto) {
        List<Long> targetUserList = userServiceClient.getUserIdsAboveTheGrade(couponCreateDto.getGrade());
        Coupon savedCoupon = couponRepository.save(couponCreateDto.toEntity());
        targetUserList.forEach(
                savedCoupon::addUserCoupon
        );

        return savedCoupon.getId();
    }
}

 

위와 같이 CouponService 에서 userServiceClient 라는 객체만 봤을 때, http 통신을 담당하는 객체인지 알지 못하도록 기능을 추상화해준다는 점Feign Client 의 장점이라고 볼 수 있겠습니다.

 

3. 테스트

앞에서 개발한 쿠폰 발급 API 가 아래와 같다고 가정해보겠습니다.

@RequiredArgsConstructor
@RestController
public class CouponController {
    private final CouponService couponService;

    @PostMapping("/coupons")
    public ResponseEntity<CouponResponse> create(@LoginPartner AuthorizedPartner partner,
                                                 @RequestBody CouponCreateRequest couponCreateRequest) {
        CouponCreateDto couponCreateDto = couponCreateRequest.toDto(partner.getId());
        Long couponId = couponService.create(couponCreateDto);

        return ResponseEntity.created(URI.create("/coupons/"+couponId)).body(
                new CouponResponse(couponId, "쿠폰이 정상적으로 등록되었습니다.")
        );
    }
}

Postman 실행 결과

 

 

 

해당 API 실행 후, 각 서비스의 로그를 확인해보면 마이크로 서비스 간 통신이 성공한 것을 확인할 수 있습니다.

사용자 마이크로 서비스에서 실행된 사용자 조회 쿼리

 

쿠폰 마이크로 서비스에서 실행된 쿠폰 발급내역 Insert 쿼리


참고 및 출처.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard

 

Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) - 인프런 | 강의

Spring framework의 Spring Cloud 제품군을 이용하여 마이크로서비스 애플리케이션을 개발해 보는 과정입니다. Cloud Native Application으로써의 Spring Cloud를 어떻게 사용하는지, 구성을 어떻게 하는지에 대해

www.inflearn.com

 

댓글