y1551463

클라이언트 사이드 로드 밸런싱 (FeignClient와 Ribbon) 실습

LoadBalancing
a month ago
·
4 min read

Eureka 서버는 서비스 디스커버리 실습에 설정한 서버 그대로 사용한다

유레카 서버 :

MSA 환경에서 서비스 레지스트리 역할을 한다

각 서비스는 자신의 메타데이터(이름, 주소, 포트 등)를 유레카 서버에 등록한다

@EnableEurekaServer 어노테이션을 통해 유레카 서버로 동작하도록 설정할 수 있다

eureka.client.register-with-eureka=false

eureka.client.fetch-registry=false 기존 프로퍼티스 설정은 서버 자체가 레지스트리 역할만 수행하게 하고, 클라이언트로 등록되지 않도록 설정

Eureka 클라이언트(Order, Product)

Order와 Product를 유레카 서버에 등록한다

spring:
  application:
    name: product-service
server:
  port: 19092
eureka:
  client:
    service-url:
      defaultZone: http://localhost:19090/eureka/

#name, port만 상이함
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {

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

}

@SpringBootApplication
@EnableFeignClients
public class ProductApplication {

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

}

// @EnableFeignClients -> Feign 클라이언트를 활성화하기 위한 어노테이션

Product는 포트를 3개 사용하므로 별도 설정 필요

포트를 다르게 설정(19092, 19093, 19094 등)하여 동일한 애플리케이션을 여러 인스턴스로 실행한다

VM 옵션에(-Dserver.port=포트번호) 추가하여 동일한 애플리케이션을 다른 포트로 실행할 수 있다

2266

ProductController 코드

@RestController
public class ProductController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/product/{id}")
    public String getProduct(@PathVariable String id) {
        return "product " + id + "info from port : " + serverPort;
    }

}

Order

OrderController

@RestController
@RequiredArgsConstructor
public class OrderController {

    private final OrderService orderService;

    @GetMapping("/order/{orderId}")
    public String getOrder(@PathVariable() String orderId) {
        return orderService.getOrder(orderId);
    }
}

OrderService

@Service
@RequiredArgsConstructor
public class OrderService {

    private final ProductClient productClient;

    public String getProductInfo(String productId) {
         return productClient.getProduct(productId);
    }

    public String getOrder(String orderId) {
        if (orderId.equals("1")) {
            String productId = "2";
            String productInfo = getProductInfo(productId);
            return "order : " + orderId + "and " + productInfo;
        } else {
            return "Not exist order";
        }
    }
}

Order에서 Product를 호출하기 위한 코드

@FeignClient(name = "product-service")
public interface ProductClient {

    @GetMapping("/product/{id}")
    String getProduct(@PathVariable String id);

}

@FeignClient 어노테이션을 통해 클라이언트 사이드 로드 밸런싱을 구현한다

  • 서비스 이름 기반 호출

    • name = "product-service"는 유레카에 등록된 product-service라는 이름의 서비스 인스턴스를 호출하겠다는 의미

  • 메서드 매핑

    • @GetMapping("/product/{id}")

      • 상품 서비스의 /product/{id} API를 호출하도록 설정하며 파라미터와 어노테이션을 통해 HTTP 요청 매핑

    • Feign 클라이언트 호출

      • ProductClientgetProduct(String id) 메서드가 호출되면 Feign은 내부적으로 HTTP 요청을 생성


결과

Order를 호출하면서 Product의 포트가 순차적으로 응답하는 것을 확인했다

해당 실습에서 Ribbon에 대한 설정은 없었는데 이는 FeignClient을 사용할 경우 Ribbon이 자동으로 통합되어 로드 밸런싱이 처리된다.

  • Ribbon의 기본 로드 밸런싱 알고리즘인 라운드로빈 방식으로 응답 결과를 확인할 수 있었다


- 컬렉션 아티클