
로드 밸런싱은 네트워크 트래픽을 여러 서버로 분산시켜 서버의 부하를 줄이고, 시스템의 성능과 가용성을 높이는 기술입니다. 서버 간 트래픽을 고르게 분배하여 특정 서버에 부하가 집중되는 것을 방지합니다.
클라이언트 사이드 로드 밸런싱은 클라이언트가 직접 여러 서버 중 하나를 선택하여 요청을 보내는 방식입니다. 클라이언트는 서버의 목록을 가지고 있으며, 이를 바탕으로 로드 밸런싱을 수행합니다.
로드 밸런서(중앙 집중 장치)가 네트워크 앞단에 위치하고 있어, 로드 밸런서가 요청을 받아서 여러 서버 인스턴스 중 하나를 선택해 전달합니다.
이때, 클라이언트는 항상 하나의 고정된 주소(로드 밸런서 주소)로 요청을 보냅니다.
둘이 차이를 쉽게 비교하자면 서버 사이드 로드 밸런싱은 "고객이 식당 들어갈 때 안내 직원이 테이블을 배정해준것" 이고 클라이언트 사이드 로드 밸런싱은 "고객이 직접 빈 테이블을 보고 앉는 것" 입니다.
이번 예제에서는 클라이언트 사이드 로드 밸런싱을 통해 주문(Order) -> 상품(Product) 로 요청을 보낼때 여러가지 상품 서버중의 하나를 선택하는 방식을 사용하겠습니다.
FeignClient는 Spring Cloud에서 제공하는 HTTp 클라이언트로, 선언적으로 RESTful 웹 서비스를 호출할 수 있습니다. Eureka와 같은 서비스 디스커버리와 연동하여 동적으로 서비스 인스턴스를 조회하고 로드 밸런싱을 수행합니다.
💡 Ribbon이란?
넷플릭스가 개발한 클라이언트 사이드 로드 밸런서로, 마이크로서비스 아키텍처에서 서비스 인스턴스 간의 부하를 분산합니다. 다양한 로드 밸런싱 알고리즘을 지원하며, Eureka와 같은 서비스 디스커버리와 연동하여 사용합니다.
주요 특징
- 서버 리스트 제공자 : Eureka 등으로부터 서비스 인스턴스 리스트를 제공받아 로드 밸런싱에 사용
- 로드 밸런싱 알고리즘 : 라운드 로빈, 가중치 기반 등 다양한 로드 밸런싱 알고리즘 지원
- 라운드 로빈 : 각 서버에 순차적으로 요청을 분배방식(간단하고 공평)
- 가중치 기반 : 각 서버에 가중치를 부여하고, 가중치에 비례하여 요청을 분배하는 방식(서버의 성능이나 네트워크 상태에 따라 조절)
- Failover: 요청 실패 시 다른 인스턴스로 자동 전환
@FeignClient(name = "my-service") 어노테이션은 Eureka에 등록된 서비스 이름을 참조my-service라는 이름으로 등록된 서비스 인스턴스 목록을 조회유레카 서버 하나에 주문 인스턴스 1개와 같은 기능의 포트만 다른 상품 인스턴스 3개를 연결합니다. 상품을 요청(http://localhost:19091/order/1) 하면 응답하는 인스턴스의 포트를 받아서 노출합니다.
이를 통해 라운드로빈으로 로드밸런싱이 되는것을 확인해보겠습니다!
유레카 서버는 이전 실습에서 사용했던 서버를 그대로 사용하겠습니다.
Order와 Produdct만 프로젝트를 새로 생성해줍니다.

기존과 같이 Spring Web, Eureka Discovery Client를 추가해주고 FeignClient를 사용하기 위한 OpenFeign 그리고 롬복사용을 위해 Lombok도 추가해줍니다.
(order도 똑같이 생성합니다)
1. 새로 만들어준 Product 애플리케이션이 기존 Eureka 서버에 연결될 수 있도록 application.yml에 설정을 추가해줍니다.
spring:
application:
name: product-service
server:
port: 19092
eureka:
client:
service-url:
defaultZone: http://localhost:19090/eureka/
2. OpenFeign 사용을 위한 설정파일을 추가하여 @EnableFeignClients 어노테이션을 붙여줍니다.
@EnableFeignClients(basePackages = "com.spring_cloud.eureka.client.product")
@Configuration
public class FeignConfig {
}
Application 클래스가 아닌 따로 설정 파일을 만들어서 추가하는 경우 적용할 패키지 경로를 함께 작성해줍니다.
3. 요청을 받을 controller를 작성해줍니다.
@RestController
public class ProductController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/product/{id}")
public String getProduct(@PathVariable("id") String id){
return "Product " + id +" info!!!!! From port : " + serverPort;
}
}
@Value를 사용하여 포트를 가져온다음 현재 응답해주는 서버가 몇번 포트인지 확인합니다.
order 애플리케이션에서도 설정을 위해 Product 와 같이 (1),(2)을 수행합니다.
3. product로 요청을 보낼 FeignClient 인터페이스를 작성해줍니다.
@FeignClient(name="product-service")
public interface ProductClient {
@GetMapping("/product/{id}")
String getProduct(@PathVariable("id") String id);
}
4. prdouctClient를 통해 상품정보를 불러오는 Order Service를 작성해줍니다.
@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. order 요청을 받을 controller를 작성해줍니다.
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping("/order/{orderId}")
public String getOrder(@PathVariable("orderId") String orderId){
return orderService.getOrder(orderId);
}
}
로드 밸런싱이 정상적으로 동작하는지 확인하기 위해 order-service는 하나, product-service는 세 개의 인스턴스를 실행시켜 실험해보았습니다. 이때 order-service에서 product-service로 요청을 보냈을 때 요청이 여러 인스턴스로 분산되는지 확인하는 것이 목표입니다.

1. 애플리케이션 실행

먼저 eureka-server와 order-service를 실행합니다.
그 다음 product-service는 ProductApplication 실행 → 복제 버튼을 이용해 세 개의 인스턴스로 띄웁니다.

각 인스턴스가 충돌하지 않도록 포트를 다르게 설정해주어야 합니다.
Add Run Options → Add VM options에서 아래와 같이 포트를 지정했습니다.
-Dserver.port=19092
-Dserver.port=19093
-Dserver.port=19094
이렇게 세 개의 포트로 실행시켜 각기 다른 인스턴스를 구동했습니다.
2. 유레카 서버 확인

유레카 서버에 접속해보면 order-service와 product-service가 정상적으로 등록된 것을 확인할 수 있습니다.
특히 product-service는 세 개의 인스턴스가 서로 다른 포트(19092, 19093, 19094)로 실행되어 있는 것이 나타납니다.
3. 실제 요청 테스트
이제 order-service를 통해 product-service에 실제 요청을 보내보았습니다.
• 첫 번째 요청: 19092 포트 인스턴스가 응답

• 두 번째 요청(새로고침): 19093 포트 인스턴스가 응답

• 세 번째 요청(다시 새로고침): 19094 포트 인스턴스가 응답

요청을 반복할 때마다 product-service 인스턴스가 번갈아 가며 응답하는 것을 확인할 수 있었습니다.