MSA 로드 밸런싱(FeignClient, Ribbon)

배지원·2025년 1월 25일

MSA

목록 보기
12/12

클라이언트 사이드 로드 밸런싱

(1) 로드 밸런싱이란?

  • 로드 밸런싱은 네트워크 트래픽을 여러 서버로 분산시켜 서버의 부하를 줄이고, 시스템의 성능과 가용성을 높이는 기술
  • 서버 간 트래픽을 고르게 분배하여 특정 서버에 부하가 집중되는 것을 방지

(2) 클라이언트 사이드 로드 밸런싱이란?

  • 클라이언트 사이드 로드 밸런싱은 클라이언트가 직접 여러 서버 중 하나를 선택하여 요청을 보내는 방식
  • 클라이언트는 서버의 목록을 가지고 있으며, 이를 바탕으로 로드 밸런싱을 수행

1. FeignClient

(1) FeignClient란?

  • FeignClient는 Spring Cloud에서 제공하는 HTTP 클라이언트로, 선언적으로 RESTful 웹 서비스를 호출할 수 있음
  • Eureka와 같은 서비스 디스커버리와 연동하여 동적으로 서비스 인스턴스를 조회하고 로드 밸런싱을 수행

(2) FeignClient의 주요 특징

  • 선언적 HTTP 클라이언트: 인터페이스와 어노테이션을 사용하여 REST API를 호출할 수 있음
  • Eureka 연동: Eureka와 통합하여 서비스 인스턴스 목록을 동적으로 조회하고 로드 밸런싱을 수행
  • 자동 로드 밸런싱: Ribbon이 통합되어 있어 자동으로 로드 밸런싱을 수행

2. Ribbon

(1) Ribbon이란?

  • 넷플릭스가 개발한 클라이언트 사이드 로드 밸런서로, 마이크로서비스 아키텍처에서 서비스 인스턴스 간의 부하를 분산
  • 다양한 로드 밸런싱 알고리즘을 지원하며, Eureka와 같은 서비스 디스커버리와 연동하여 사용

(2) Ribbon의 주요 특징

  • 서버 리스트 제공자: Eureka 등으로부터 서비스 인스턴스 리스트를 제공받아 로드 밸런싱에 사용
  • 로드 밸런싱 알고리즘: 라운드 로빈, 가중치 기반 등 다양한 로드 밸런싱 알고리즘 지원
  • Failover: 요청 실패 시 다른 인스턴스로 자동 전환

FeignClient와 Ribbon 동작 원리

  1. 서비스 이름: @FeignClient(name = "my-service") 어노테이션은 Eureka에 등록된 서비스 이름을 참조
  2. 서비스 인스턴스 조회: Eureka 서버에서 my-service라는 이름으로 등록된 서비스 인스턴스 목록을 조회
  3. 로드 밸런싱: 조회된 서비스 인스턴스 목록 중 하나를 선택하여 요청을 보냅니다. 이는 기본적으로 Ribbon을 사용하여 로드 밸런싱을 수행
  4. 요청 분배: 여러 서비스 인스턴스가 있을 경우, Round Robin 또는 다른 설정된 로드 밸런싱 알고리즘을 사용하여 요청을 분배

3. 실습

  • Order서비스는 Product서비스를 호출하여 상품 정보를 가져오는 시스템을 만들어보도록 하겠습니다.

  1. Order 서비스 실행: Order 서비스가 실행되면 Eureka 서버에서 Product 서비스 인스턴스 목록을 가져옵니다.
  2. Product 서비스 호출: Order 서비스에서 Product 서비스의 정보를 가져오기 위해 FeignClient를 사용하여 호출합니다.
  3. Ribbon을 통한 로드 밸런싱: FeignClient는 Ribbon을 통해 3개의 Product 인스턴스 중 하나를 선택하여 호출합니다. 이 과정에서 Round Robin 알고리즘을 사용하여 요청을 순차적으로 분배합니다.
  4. 응답 처리: 선택된 Product 인스턴스에서 응답을 받아 Order 서비스에 반환하고, 최종적으로 클라이언트에 응답을 전달합니다.

(1) 기본 설정

  • FeignClient와 Ribbon을 사용하려면 Spring Boot 애플리케이션에 의존성을 추가해야 함

[1] build.gradle 파일

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}

(2) FeignClient와 Eureka 연동

[1] application.yml 파일

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

(3) Product instance 설정

  • Product는 요청이 오면 아래의 문자열을 반환합니다.
    ”Product {productId} info!!!! From port : ${serverPort}”

[1] Spring Boot 애플리케이션 설정

@SpringBootApplication
@EnableFeignClients
public class OrderApplication {

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

[2] ProductController

@RestController
@RequiredArgsConstructor
public class OrderController {
    
    private final OrderService orderService;

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

[3] ProductClient

@FeignClient(name = "product-service")
public interface ProductClient {
    @GetMapping("/product/{id}")
    String getProduct(@PathVariable("id") String id);
}

[4] 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 "Your order is " + orderId + " and " + productInfo;
        }
        return "Not exist order...";
        }
    }
 }

[5] 19092,19093,19094 포트에 같은 애플리케이션 실행하기

- Intellij에서 실행 애플리케이션 Edit Configurations 클릭

- Add New Configuration를 통해 기존 ProductApplicaion을 복사하여 총 3개를 만들어 줍니다.

- Add Vm Options를 통해 복사한 Application마다 별도의 포트번호를 지정해 줍니다.
- "Dserver.port=19092"를 입력하여 각 포트번호를 지정해 줍니다.

(4) Order instance 설정

  • Order는 요청이 오면 product를 호출하여 상품의 정보를 가져옵니다. 그리고 아래의 문자열을 반환합니다.
    ”Your order {orderId} product info => ${프로덕트에서 받은 문자열}”

[1] Spring Boot 애플리케이션 설정

@SpringBootApplication
@EnableFeignClients
public class ProductApplication {

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

}

[2] ProductController

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@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 ;
    }
}

4. 결과

profile
Web Developer

0개의 댓글