로드 밸런싱
로드 밸런싱은 네트워크 트래픽을 여러 서버로 분산시켜 서버의 부하를 줄이고, 시스템의 성능과 가용성을 높이는 기술.
서버 간 트래픽을 고르게 분배하여 특정 서버에 부하가 집중되는 것을 방지.
종류 : 클라이언트 사이드 로드 밸런싱, 서버 사이드 로드 밸런싱
클라이언트 사이드 로드 밸런싱
클라이언트 사이드 로드 밸런싱은 클라이언트가 직접 여러 서버 중 하나를 선택하여 요청을 보내는 방식.
클라이언트는 서버의 목록을 가지고 있으며, 이를 바탕으로 로드 밸런싱을 수행.
FeignClient
FeignClient는 Spring Cloud에서 제공하는 HTTP 클라이언트로, 선언적으로 RESTful 웹 서비스를 호출 할 수 있음.
Eureka와 같은 서비스 디스커버리와 연동하여 동적으로 서비스 인스턴스를 조회하고 로드 밸런싱을 수행.
주요 특징
- 선언적 HTTP 클라이언트 : 인터페이스와 어노테이션을 사용하여 REST API를 호출 할 수 있음
- Eureka 연동 : Eureka와 통합하여 서비스 인스턴스 목록을 동적으로 조회하고 로드 밸런싱 수행
- 자동 로드 밸런싱 : Ribbon이 통합되어 있어 자동으로 로드 밸런싱을 수행
Ribbon
넷플릭스가 개발한 클라이언트 사이드 로드 밸런서로, 마이크로서비스 아키텍처에서 서비스 인스턴스 간의 부하를 분산.
다양한 로드 밸런싱 알고리즘을 지원하며, Eureka와 같은 서비스 디스커버리와 연동하여 사용.
주요 특징
- 서버 리스트 제공자 : Eureka 등으로부터 서비스 인스턴스 리스트를 제공받아 로드 밸런싱에 사용
- 로드 밸런싱 알고리즘 : 라운드 로빈, 가중치 기반 등 다양한 로드 밸런싱 알고리즘 지원
- Failover : 요청 실패 시 다른 인스턴스로 자동 전환
FeignClient와 Ribbon 기본 설정
SpringBoot 어플리케이션에 의존성 추가하기
build.gradle
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}
SpringBoot 애플리케이션 설정
@SpringBootApplication
@EnableFeignClients
public class MyServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MyServiceApplication.class, args);
}
}
어노테이션으로 @EnableFeignClients 추가
FeignClient 인터페이스 작성
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "my-service")
public interface MyServiceClient {
@GetMapping("/endpoint")
String getResponse(@RequestParam(name = "param") String param);
}
@FeignClient 선언 ( ) 안에는 호출하고자 하는 호스트 이름 작성
인터페이스 안에는 호출하고자 하는 endpoint 작성
FeignClient와 Ribbon의 동작 원리
- 서비스 이름: @FeignClient(name = "my-service") 어노테이션은 Eureka에 등록된 서비스 이름을 참조
- 서비스 인스턴스 조회: Eureka 서버에서 my-service라는 이름으로 등록된 서비스 인스턴스 목록을 조회
- 로드 밸런싱: 조회된 서비스 인스턴스 목록 중 하나를 선택하여 요청을 보냅니다. 이는 기본적으로 Ribbon을 사용하여 로드 밸런싱을 수행
- 요청 분배: 여러 서비스 인스턴스가 있을 경우, Round Robin 또는 다른 설정된 로드 밸런싱 알고리즘을 사용하여 요청을 분배
실습
유레카 서버에 주문 인스턴스와 같은 기능의 포트만 다른 상품 인스턴스 3개 연결하기.
상품을 요청하면 응답하는 인스턴스의 포트번호를 노출해 라운드로빈 방법으로 로드 밸런싱이 되는지 확인한다.
👉🏻 https://start.spring.io/ 에서 order와 product 프로젝트 생성
이전 글에서 만들었던 Eureka 서버를 재사용할 것이기 때문에 같은 폴더로 옮겨주고 firstClient와 secondClient는 삭제.
2024.08.17 - [Spring/MSA] - 서비스 디스커버리 Eureka 이해하기 및 실습
ProductClient 설정
ProductController.java
@RestController
public class ProductController {
@Value("${server.port}")
private String port;
@GetMapping("/product/{id}")
public String getProduct(@PathVariable("id") String id) {
return "Product : " + id + " info!! From port : " + port;
}
}
@value 어노테이션을 사용하면 application.properties 또는 application.yml에 있는 값을 가져올 수 있다.
application.yml
spring:
application:
name: product-service
server:
port: 19092
eureka:
client:
service-url:
defaultZone: http://localhost:19090/eureka/
기존에 있던 application.properties를 삭제하고 yml 파일을 만든다. (둘 다 동일한 설정 파일이기에 yml파일로 만드는 법 연습)
동일한 인스턴스지만 포트번호만 다른 product을 3개 만들기 위해 다음과 같이 복제해준다. 구분을 위해 이름 뒤에 포트번호 추가.
복제된 product의 포트 번호를 바꾸기 위해 옵션의 VM 추가하기로 "-Dserver.port=포트번호" 다음과 같이 추가한다.
이제 유레카 서버를 실행시키고 Product 또한 실행시킨 뒤 위에서 설정한 엔드포인트로 접속하게되면 위와 같이 뜨는 것을 확인 할 수 있다.
OrderClient 설정
동작 원리 : OrderController로 요청이 들어오면 Eureka 서버에 등록된 FeignClient인 product을 찾아 반환. product을 찾는 방법은 라운드로빈 사용.
ProductClient.java
@FeignClient(name="product-service")
public interface ProductClient {
@GetMapping("/product/{id}")
String getProduct(@PathVariable("id") String id);
}
FeignClient인 product를 받아오기 위해 ProductClient 인터페이스를 만들어준다. Product들은 "product-service"라는 이름으로 등록이 되어 있기 때문에 위와 같은 어노테이션으로 찾아야 할 이름을 알려준다.
OrderController.java
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping("/order/{orderId}")
public String getOrder(@PathVariable("orderId") String orderId) {
return orderService.getOrder(orderId);
}
}
OrderController로 들어온 요청은 orderId를 받아 OrderService로 넘겨주게된다.
OrderService.java
@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;
}else {
return "Not Exist";
}
}
}
OrderService에서는 받아온 orderId를 이용해 Product 정보를 가져와 반환한다. 위에서 사용한 if/else문은 단순한 유효성 검사이다.
productId를 임의로 "2"라고 주었을 때 product의 getProduct를 호출해서 정보를 받아오면 모든 어플리케이션을 실행했을 때 다음과 같은 창이 뜬다.
같은 엔드포인트에 계속 접근하면 포트번호만 바뀐 채 같은 결과가 뜨는 것을 확인 할 수 있는데 이것으로 인해 라운드로빈 알고리즘이 쓰였음을 확인 할 수 있다.
'Spring' 카테고리의 다른 글
Spring 공통 모듈 & 공통 DTO 사용하기 (0) | 2024.10.01 |
---|---|
서킷 브레이커 Resilience4j와 API 게이트웨이 이해하기 (1) | 2024.08.17 |
서비스 디스커버리 Eureka 서버 이해하기 및 실습 (0) | 2024.08.17 |
MSA와 Spring Cloud 이해하기 (0) | 2024.08.17 |
Spring의 RestTemplate 이해하기 (0) | 2024.08.17 |