본문 바로가기
web/SpringBoot

[MSA] Spring Cloud를 사용해보자(4)-로드밸런서

by 뽀리님 2023. 11. 28.

목표

EurekaServer Service Client 구현 , Ribbon 통해 라운드로빈방식으로 호출하는 ClientSide Service discovery 패턴의 구현  

 

Netflix Eureka를 통해 Eureka Server(서비스 레지스트리)를 구현한 후,

https://ssmyefrin.tistory.com/43

 

[MSA] Spring Cloud를 사용해보자(3)-API Gateway

기존에 있던 모놀리식 아키텍처를 msa 로 구현해보는 과정에서 API Gateway 로 Spring Cloud 를 이용하기로 했다. 그전에 MSA와 DevOps, K8S 등의 개념을 알고 가는게 좋을꺼 같아 퍼왔다. 참조하면 좋을꺼같

ssmyefrin.tistory.com

 

 

Service-a, Service-b(1), Service-b(2) 3개의 Eureka 클라이언트 서비스 를 구성하여

Service-a에서 2개의 인스턴스인 Service-b 라운드로빈 방식으로 호출하는 ClientSide Service discovery 구현해보자.

 

✔ 실행환경

- IntelliJ + SpringBoot 3.1.5 + Gradle + OpenJDK17
- Eureka 서버
- MacOS

 

 

 

Service-a (로드밸런서)

 

1. 프로젝트 생성

의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

 

 

2. 로드밸런스 Bean 생성 (따로 빼지않고 Application에 만듬)

@EnableDiscoveryClient
@SpringBootApplication
public class AccountApplication {

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

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

 

서비스간 통신을 위해 RestTemplate을 이용하고 @LoadBalanced 어노테이션을 추가해준다.

@LoadBalenced는 Eureka에 내장된 로드밸런서인 Ribbon을 이용해 라운드 로빈을 기반으로 서비스 인스턴스를 호출할 수 있다. 즉, 어노테이션 추가만으로 Service-A에서 2개의 인스턴스인 Service-B를 자동으로 라운드 로빈 기반으로 호출할 수 있다.

 

3. 프로퍼티추가

spring:
  application:
    name: lb-service       # 서비스를 구분할 name

server:
  port: 8004

eureka:
  instance:
    instance-id: inst001   # 동일한 서비스 name에서 인스턴스 구분자
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka     # 클라이언트가 속할 Eureka Server

 

 

4. 컨트롤러 생성

@RestController
@RequiredArgsConstructor
@Slf4j
public class AccountController {
    private final RestTemplate restTemplate;
    private static final String SERVICE_B_NAME = "backend-service";

    @GetMapping("/test")
    public String callServiceA() throws UnsupportedOperationException, IOException {
        ResponseEntity<String> res;
        String apiPath = "/todo/check";
        res = restTemplate.getForEntity("http://" + SERVICE_B_NAME + apiPath, String.class);
        return "Account-API : inst001 호출" + " > " + res.getBody().toString();
    }
}

 

 

 

Service-b(1)

 

1. 프로젝트생성

의존성추가

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

 

2.  프로퍼티생성

server:
  port: 8005
logging:
  level:
    com:
      msa:
        todo2: debug
spring:
  application:
    name: backend-service

eureka:
  instance:
    instance-id: inst001
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka

서비스명은 backend-service 다.

 

3. 컨트롤러생성

@RestController
@RequiredArgsConstructor
public class TodoController2 {
    @GetMapping("/todo/check")
    public String check() {
        return "backend-service : inst001 정상";
    }
}

 

 

4. 어플리케이션에 어노테이션추가

@EnableDiscoveryClient
@SpringBootApplication
public class TodoApi2Application {

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

}

 

 

 

-- 동일하게 Service-b(2) 도 만들어준다(동일한서비스명, 인스턴스 이름만 다르게)

 

 

5.테스트

 

인스턴스 1 호출
인스턴스&nbsp; 2 호출