1. 로드 밸런싱이란?
네트워크 트래픽을 여러 서버에 고르게 분산시켜 서버의 과부하를 방지하고 서비스의 가용성을 높이는 기술을 말한다. 이를 통해 특정 서버에 트래픽이 집중되는 것을 막고, 시스템의 성능과 안정성을 유지할 수 있다. 로드밸런서는 다양한 알고리즘을 사용하여 요청을 적절한 서버로 라우팅한다. 이러한 알고리즘에는 라운드 로빈, 최소 연결, IP 해시, 가중치 기반 등이 포함된다.
2. 클라이언트 사이드 로드 밸런싱
로드 밸런싱은 클라이언트 사이드와 서버 사이드로 나뉘며, 두 방식은 각각의 장단점을 가지고 있다.
클라이언트 사이드 로드 밸런싱은 주로 마이크로서비스 아키텍처에서 사용되며, Netflix Ribbon과 같은 라이브러리를 통해 구현할 수 있다. 반면, 서버 사이드 로드 밸런싱은 AWS ELB와 같은 서비스에서 제공하는 기능으로, 중앙 집중화된 관리와 보안 강화가 가능하다.
3. Netflix Ribbon
Netflix Ribbon은 클라이언트 사이드 로드 밸런서로, 클라이언트 측에서 직접 로드 밸런싱을 수행하는 방식이다. 이는 클라이언트가 서버 목록을 가지고 있으며, 그 목록에서 적절한 서버로 요청을 분산시키는 역할을 한다. Ribbon은 소프트웨어 기반으로 동작하며, 하드웨어 장비 없이도 부하 분산을 가능하게 한다.
Ribbon은 주로 마이크로서비스 아키텍처에서 사용되며, 서비스 인스턴스 간의 부하를 효과적으로 분산시킨다. 주로, Eureka와 같은 서비스 디스커버리 시스템과 통합되어 사용된다. 동적으로 서버 목록을 갱신하고 관리할 수 있다.
4. 실습
유레카 서버에 order 기능을 제공하는 서버 인스턴스 1개와 product 기능을 제공하는 서버 인스턴스 3개를 띄우고,
order의 기능을 사용할 때, product의 정보를 가져와야 하는 상황이다.
3개의 인스턴스가 라운드 로빈 방식으로 부하 분산이 일어나는지 확인해본다.
Netflix Ribbon의 기본 로드 밸런싱 알고리즘이 라운드 로빈(Round Robbin) 방식이다.
5. 라운드 로빈(Round Robin)
실습 전에 라운드 로빈 방식부터 알아보자. 라운드 로빈은 여러 분야에서 사용되는 공정한 분배 방식으로, 주로 로드 밸런싱과 CPU 스케줄링에서 활용된다. 이 알고리즘은 요청이나 작업을 순환적으로 할당하여 각 대상이 공평하게 기회를 얻도록 한다.
5 - 1. 라운드 로빈의 특징
5 - 1 - 1. 순환적 할당
서버 A, B, C가 있을 때, 첫 번째 요청은 서버 A에, 두 번째 요청은 서버 B에, 세 번째 요청은 서버 C에 전달되며, 이후 다시 서버 A로 돌아가게 된다.
5 - 1 - 2. 공정성
모든 대상이 동일한 기회를 얻기 때문에 공정한 자원 분배가 가능하다. 이는 특히 모든 대상의 성능이 비슷할 때 유용하다.
5 - 1 - 3. 단순성
구현이 간단하고 효율적이다. 복잡한 계산 없이 순서대로 할당하기 때문에 관리가 용이하다.
6. 진짜 실습
6 - 1. order
6 - 1 - 1. build.gradle(order)
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.5'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.spring-cloud.eureka.client'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "2023.0.3")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
web, eureka-client, openfeign, lombok
의존성을 추가했다.
openfeign으로 product를 호출한다.
Spring Cloud 환경에서는 `@FeignClient` 어노테이션을 사용할 때 자동으로 Ribbon이 적용된다.
6 - 1 - 2. application.yml
spring:
application:
name: order-service
server:
port: 19091
eureka:
client:
service-url:
defaultZone: http://localhost:19090/eureka/
6 - 1 - 3. OrderApplication
package com.spring_cloud.eureka.client.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
`@EnableFeignClients` 를 달아주었다.
스프링 부트 애플리케이션에서 FeignClient를 활성화 한다.
FeignClient 인터페이스를 찾아가서 구현체를 만들어주고,
이를 통해 다른 서비스에 HTTP 요청을 보낼 수 있게 된다.
6 - 1 - 4. ProductClient
package com.spring_cloud.eureka.client.order;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/product/{id}")
String getProduct(@PathVariable("id") String id);
}
`@FeignClient` 의 name으로 지정한 값은 Eureka Server에 등록된 서버 인스턴스 이름이다.
FeignClient 는 Eureka Server 에서 해당 이름으로 조회한다. 그리고 로드 밸런싱을 통해 적절한 인스턴스를 호출한다.
물론, Ribbon이 해준다.
6 - 1 - 5. OrderController, OrderService
package com.spring_cloud.eureka.client.order;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
@GetMapping("/order/{orderId}")
public String getOrder(@PathVariable("orderId") String orderId) {
return orderService.getOrder(orderId);
}
}
--- 아래는 OrderService
package com.spring_cloud.eureka.client.order;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.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...";
}
}
OrderService에서 ProductClient를 호출해서 product 서버와 통신한다.
6 - 2. product
package com.spring_cloud.eureka.client.product;
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("id") String id) {
return "Product " + id + " info!!!!! From port : " + serverPort ;
}
}
7. 실행
자 이제 Eureka Server 와 OrderApplication 1개, ProductApplication 3개를 띄우고
http://localhost:19091/order/1
를 여러 번 호출해보자.
기대하는 것은 product-service의 3개 인스턴스가 골고루 호출이 되는 것이다.
원하는 결과가 나왔다!
라운드 로빈 방식에 의해 3개 인스턴스가 골고루 호출이 되었다.
'MSA' 카테고리의 다른 글
2024 11 28 TIL - Spring Cloud Config (1) | 2024.11.28 |
---|---|
2024 11 27 TIL - API Gateway, Spring Cloud Gateway (0) | 2024.11.27 |
2024 11 26 TIL - CircuitBreaker(Resilience4j) (0) | 2024.11.26 |
2024 11 22 TIL - Spring Cloud Netfilx Eureka로 알아보는 서비스 디스커버리 (3) | 2024.11.22 |
2024 11 21 TIL - MSA란? (1) | 2024.11.21 |