MSA에서 Service Discovery를 쓰는 이유?

Service Discovery란 클라이언트의 요청 정보에 따라 필요한 서비스의 위치를 알려주는 역할을 하는 기능입니다. 

클라우드 환경에서 동작하는 MSA 서비스는 동적인 IP 주소와 포트를 사용하는 인스턴스를 만들게 되는데, 이러한 잦은 인스턴스 생성으로 인해 호출 서비스가 어떤 IP와 포트를 사용하는지 알아야 합니다. 이러한 서비스 인스턴스의 IP/Port를 찾아 호출해주는 기능을 제공하는 서버가 서비스 디스커버리의 역할입니다.

 

Service Discovery

위 그림처럼 각각의 서비스 인스턴스를 Service Registry에 등록한 후, 해당 서비스를 호출할때마다 Service Discovery 수행 과정을 거쳐 요청 정보마다 서비스를 찾아줍니다.

 

스프링부트 Spring Cloud Netflix Eureka 서버 프로젝트 생성

스프링은 이러한 Service Discovery 역할을 Eureka Server로 제공합니다. 이러한 유레카 서버를 스프링부트 2.X와 Eureka 의존성을 추가하여 생성합니다.

 start.spring.io 사이트에서 다음과 같이 프로젝트를 생성하였으며, Dependency에서 Eureka Server를 추가하여야 스프링에서 제공하는 spring-cloud-netflix-Eureka Server를 사용할 수 있습니다.

 

스프링부트 Eureka 서버 설정 및 기동

pom.xml

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>2.7.15</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>myspringcloud</groupId>
<artifactId>discoveryservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>discoveryservice</name>
<description>Demo project for Spring Boot</description>
<properties>
   <java.version>11</java.version>
   <spring-cloud.version>2021.0.8</spring-cloud.version>
</properties>

프로젝트를 생성하고 pom.xml을 확인해보면 spring-cloud.version과 spring-boot-starter 버전을 볼 수 있습니다. 해당 버전이 맞지 않을 경우 오류가 날 수 있으니, 오류가 날시 버전 체크가 필요합니다.

 

application.yml

server:
  port: 8761
spring:
  application:
    name: discoveryservice
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

resources/application.properties 파일의 이름을 yml로 바꿔주고 다음과 같이 설정합니다.

서버 포트는 8761번을 사용하며, 어플리케이션 이름을 discoveryservice라고 정의하였습니다. 이름은 다르게 설정해도 무관합니다. eureka.client 하위 설정을 false로 한 이유는 default 설정으로 true로 되어있기 때문에 해당 설정이 true로 되어있다면 유레카 서버가 자기 자신의 서비스 정보도 유레카 클라이언트로 등록하겠다는 의미입니다. 이러한 설정은 필요하지 않기 때문에 false로 설정하여 자기 자신을 등록하지 않고 서버로만 기동하도록 하는 설정입니다.

 

DiscoveryServiceApplication

main이 있는 class를 들어가게 되면 @EnableEurekaServer 어노테이션 설정이 추가되어 있지 않기 때문에 추가해줍니다. 해당 어노테이션이 없을 경우 유레카 서버로 등록되지 않아 실행시 오류가 발생합니다.

 

서버를 기동 후, localhost:8761 주소를 들어가게 되면 다음과 같이 스프링에서 제공하는 Eureka Server UI를 볼 수 있습니다. 해당 화면이 정상적으로 뜬다면 유레카 서버로써의 기본 설정은 완료됩니다.

 

스프링부트 Eureka 클라언트 서비스 프로젝트 생성

다음은 Eureka Server가 관리할 Eureka Client 서비스 인스턴스 서버를 만들어보겠습니다.

Dependency 목록으로는 Eureka Discovery Client, Lombok, Spring Boot DevTools, Spring Web을 추가하여 프로젝트를 생성하였습니다.

 

스프링부트 Eureka 클라이언트 설정 및 기동

application.yml

server:
  port: 9001
spring:
  application:
    name: user-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

Eureka 클라이언트 서비스 프로젝트 포트는 9001번을 사용할것이며, spring.application.name을 user-service로 등록하게 되면 Eureka 서버가 해당 서비스 서버명을 user-service로 인식하게 됩니다.  register-with-eureka: true로 설정하게 되면 해당 서버를 Eureka Client로 등록하게 됩니다. Service Registry에 등록한다는 의미와 같습니다. fetch-registry: true는  Eureka 서버로부터 인스턴스들의 정보를 주기적으로 가져오겠다는 설정입니다. 마지막으로 service-url.defaultZone은 등록하고자 하는 Eureka 서버의 엔드포인트 주소입니다.

 

UserServiceApplication

main 클래스 파일을 열어 @EnableDiscoveryClient 설정을 추가해줍니다. 해당 설정을 추가하지 않을시 Eureka Client로 등록되지 않기 때문에 추가해줘야 합니다.

 

Eureka Client 서비스를 등록후  Eureka Server의 주소로 접근한다면 인스턴스로 등록된 USER-SERVICE 어플리케이션을 볼 수 있으며, 설정했던  application의 name과 port로  등록이 된 것을 확인할 수 있습니다. 해당 인스턴스 정보는 Eureka Client의 서버가 기동 되어 있을때만 UI에 표시가 됩니다.

 

 

Eureka 클라이언트 인스턴스 등록

위에서 만든 Eureka Server와 Eureka Client를 기반으로 여러개의 서비스 인스턴스를 생성하는 예제를 해보겠습니다.

클라이언트 서비스 서버를 실행하여 인스턴스를 만드는 기본적인 방법 3가지를 소개합니다.

 

1. IntelliJ Run 실행

InteliJ 우측 상단의 화살표를 클릭하여 실행하는 일반적인 방법입니다. 해당 실행은 yml 파일을 참조하여 서비스 인스턴스를 생성합니다.

 

2. IntelliJ - Edit Configurations - Add VM Options 실행

IntelliJ 무료 버전을 사용할 경우의 설정 방법으로 Copy Configuration으로 설정을 복사하여 Modify options의 Add VM Options를 추가해주어야 합니다.

VM Option를  -Dserver.port=9002로 설정하게 될 경우 해당 어플리케이션은 9002번 포트로 실행이 됩니다. 이렇게 설정을 해줄 경우 포트의 중복을 피할 수 있습니다.

 

3.  CMD maven command 실행 방법

cmd 커맨드에서 mvn 커맨드가 설치되어 있는 경우에 사용할수 있으며, 실행하고자 하는 어플리케이션 root 경로로 이동하여 위와 같은 명령을 실행합니다.

mvn spring-boot:run -Dspring-boot.run.jvmArguments='-Dserver.port=9003'

실행시 포트를 9003번으로 기동하도록 하여 포트가 꼬이지 않게 실행 됩니다.

 

위 3가지 방법으로 같은 서비스를 9001, 9002, 9003 포트로 실행시 Eureka Server UI에서 3개의 Instance가 생성된 것을 볼 수 있습니다. 하지만 동적으로 인스턴스가 생성되지 않습니다. 이러한 문제를 스프링에서는 랜덤 포트를 부여함으로써 자동 생성해줄 수 있습니다.

Eureka 클라이언트 인스턴스 랜덤 포트 생성 방식

위와 같은 서비스 인스턴스 포트를 자동으로 부여해주는 방법이 랜덤 포트 방식입니다. 스프링은 기본적으로 서버 포트를 0 으로 설정시 포트를 자동으로 부여해줍니다. 해당 설정을 위해 yml 파일을 변경해줍니다.

 

application.yml

server:
  port: 0
spring:
  application:
    name: user-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

VM Option을 지운 후 다시 각각의 동일한 어플리케이션을 실행하여 Eureka Server UI를 확인해본 결과 아래와 같이 보이게 됩니다.

Build 결과에 보이는 내용으로는 각각 다른 포트로 성공적으로 올라간것으로 보이지만, UI에서는 0번포트의 인스턴스 1개만 실행 된것을 볼 수 있습니다. 이렇게 생성된 이유는 Eureka Server가 Client yml의 application name과 port를 읽기 때문에 동일한 설정 정보이기 때문에 하나의 인스턴스로 생성되게 됩니다. 이런 문제를 해결하기 위해서 yml의 설정을 다시 수정해줍니다.

 

application.yml

server:
  port: 0
spring:
  application:
    name: user-service

eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

eureka.instanc.instance=id : ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}} 설정을 추가해주면 random.value를 사용해 인스턴스ID를 랜덤한 값으로 생성하겠다는 의미입니다. 이렇게 설정하게 되었을때 클라이언트 인스턴스는 랜덤한 포트를 가지는 랜덤한 인스턴스 ID로 생성되게 됩니다. 그 결과는 아래 화면과 같이 보입니다.

위와 같이 랜덤한 값으로 인스턴스ID가 할당되어 정상적으로 다수의 인스턴스가 생성된 것을 확인할 수 있습니다.

 

 

정리

위와 같은 과정을 클라우드 환경의 MSA 구조에서는 서비스 인스턴스를 자동으로 Scale-Out 해 주며, 로드 밸런싱을 통해 서버의 부하여부에 따라 인스턴스를 선택하게 해줍니다. 이러한 기능을 Spring Cloud Eureka Server가 Service Directory의 역할을 대체하여 수행하게 됩니다.

'MSA' 카테고리의 다른 글

[MSA] API Gateway Service - Spring Cloud Routing Gateway  (2) 2023.12.28
[MSA]MSA와 Monolithic의 차이점  (0) 2023.08.26

+ Recent posts