dayne의 블로그

Spring Cloud Eureka 개념 및 프로세스 본문

Spring/Spring Cloud Eureka

Spring Cloud Eureka 개념 및 프로세스

dayne_ 2024. 11. 6. 15:35

목차

1. Service Registry & Discovery

2. Eureka

3. Eureka Server & Client 구축

 

 


1. Service Registry & Discovery

클라우드가 아닌 환경에서, 서비스의 발견은 '로드 밸런서'를 통해 해결되었습니다.

로드 밸런서가 서비스에 대한 프록시 역할을 하므로 서비스에 매핑된 정보가 있어야 하는데, 이러한 매핑 규칙을 수동으로 정의해야 하기 때문에 인프라 스트럭처의 복잡도가 증가한다는 불편한 점이 존재했습니다. (새로운 서비스를 인스턴스 시작 시점이 아닌 수동으로 등록)

 

MSA로 설계된 환경에서는, 여러 마이크로 서비스들을 운용하기 위해서 클라우드 환경에서 인스턴스를 생성하여 구축할 것입니다.

이때 클라우드 환경에서 인스턴스는 AutoScaling, 생성, 삭제, 확장 등을 거치면서 IP나 Port들이 동적으로 변경될 가능성이 많습니다.

(AutoScaling : 사용자 정의 주기 또는 이벤트에 따라 서버를 자동으로 생성하거나 삭제하는 것, 서버를 자동으로 늘리거나 줄여 비용 부담을 줄이고 원활한 서비스 제공 가능)

수십 ~ 수백개의 서비스들에 대해 이러한 변경사항들을 일일이 발견하고 수정하기에는, 관리가 어려워질뿐더러 클라이언트가 원하는 정보를 얻기 위해 요청할 서비스를 찾는 과정에서 어려움이 있습니다.

 

마이크로 서비스가 자신의 서비스를 동적으로 등록하여 스스로 라이프 사이클을 관리할 수 있도록 하고, 서비스가 등록되면 서비스 탐색 대상에 포함되어 발견 가능하도록 함으로써 수동화를 피하고 자동화하는 것이 좋습니다.

 

이러한 자동화를 지원하기 위해 MSA 환경에서는 'Service Discovery 매커니즘'을 사용합니다.

 

Service Discovery 매커니즘은 다음과 같은 역할을 수행합니다.

서비스의 위치 (IP, Port 등)를 저장 및 관리하는 서비스의 주소록 역할

 

여기서 ''서비스의 위치를 저장 및 관리하는 서비스의 주소록' 이 바로 'Service Registry' 입니다.

 

따라서 Service Discovery 메커니즘은 Service Registry를 구성하여 구현하는 것입니다.

 

<Service Discovery 매커니즘 특징>

  • Peer to Peer
    • 서비스 디스커버리 클러스터의 각 노드는 서비스 인스턴스의 상태를 공유
  • 부하 분산
    • 서비스 디스커버리는 요청을 동적으로 분산
    • 정적이며 수동으로 관리되는 로드 밸런스가 '서비스 디스커버리'로 대체됨
  • 회복성
    • 서비스 디스커버리의 클라이언트(서비스)는 각각의 서비스 정보를 로컬에 캐시하여 '서비스 디스커버리 서비스'가 가용하지 않을 때도 로컬 캐시에 저장된 정보를 기반으로 동작
  • 장애 내성
    • 서비스 디스커버리는 서비스 인스턴스의 비정상을 탐지하고 가용 서비스 목록에서 인스턴스를 제거

 

<서비스 디스커버리 메커니즘 구현을 위한 4가지 개념>

  • 서비스 동적 등록
    • 서비스를 서비스 디스커버리 에이전트(Service Registry)에 어떻게 등록하는가?
  • 서비스 동적 발견
    • 서비스 클라이언트가 어떻게 서비스 정보를 검색하는가?
  • 정보 공유
    • 서비스 정보를 어떻게 공유하는가?
  • 상태 모니터링
    • 서비스가 자신의 가용 정보를 어떻게 전달하는가?

 

1.1 서비스 동적 등록 및 정보 공유

서비스 인스턴스가 시작될 때, 자신의 물리적 위치와 경로, 포트(IP, PORT 등)를 Service Registry에 등록합니다.

각 인스턴스에는 고유 IP 주소와 포트가 있지만, 동일한 서비스 ID로 등록합니다.

(서비스 ID : 동일한 서비스 인스턴스 그룹을 식별하는 키)

서비스는 1개의 서비스 디스커버리 인스턴스에만 등록하며, 서비스가 등록되면 서비스 디스커버리는 'Peer to Peer'로 클러스터에 있는 다른 노드에 전파합니다.

 

1.2 서비스 동적 발견

Service Registry에서 현재 가용 중인 필요한 서비스를 호출할 수 있게 해 줍니다.

즉, 정적으로 서비스 URL을 설정하고 관리하는 대신 Service Registry를 통해 그때그때 사용 가능한 URL을 발견할 수 있게 됩니다.

또한 빠른 처리를 위해 서비스 인스턴스들은 주기적으로 Service Registry의 데이터를 로컬에 캐시하여, 원하는 서비스 호출 시마다 캐싱된 데이터에서 위치 정보를 검색합니다. 서비스 호출이 실패하면 로컬에 있는 캐시는 무효화가 되고 Service Registry로부터 새로운 정보를 받아옵니다.

 

1.3 상태 모니터링

인스턴스들은 주기적으로 신호를 보내 자신의 상태를 Service Registry에 알립니다. Service Registry는 특정 서비스로부터 이러한 신호가 일정 횟수 이상 도착하지 않으면 가용할 수 없는 서비스로 간주하여 해당 서비스를 제외시킵니다.

 

 


2. Eureka

Eureka 는 자가 등록, 동적 발견 및 부하 분산을 담당하며 위의 서비스 디스커버리 메커니즘을 구현할 수 있도록 도와줍니다. 클라이언트 측 부하 분산을 위해 내부적으로 Ribbon을 사용하므로, 이미 Ribbon을 사용하고 있다면 제거 가능합니다.

 

※ Ribbon

  • Netflix에서 개발한 '클라이언트 사이드 로드 밸런서'로, Eureka와 함께 사용하여 서비스 디스커버리와 로드 밸런싱을 자동으로 처리
  • 예를 들어 클라이언트가 서비스 A를 요청할 때, Ribbon은 Eureka로부터 A의 여러 인스턴스를 가져오고 그중에서 가장 적합한 인스턴스를 선택하여 요청 전달) 

Eureka는 Server 컴포넌트와 Client 컴포넌트로 구성되어 있습니다.

  • Eureka Server
    • 모든 마이크로 서비스가 자신의 가용성을 등록하는 Registry
    • 등록되는 정보는 서비스 ID와 URL이 포함되는데, 마이크로 서비스는 Eureka Client를 이용해 해당 정보를 Eureka Server에 등록
  • Eureka Client
    • 등록된 마이크로 서비스를 호출해서 사용할 때 Eureka Client를 이용해서 필요한 서비스를 발견
    • Eureka Server는 Eureka Server인 동시에, 서로의 상태를 동기화하기 때문에 서로를 바라보는 Eureka Client이기도 함 (= 다른 Eureka Server와 상태 동기화)
      • 이러한 점은 Eureka Server의 고가용성을 위해 여러 대의 Eureka Server 운용 시 유용

 

2.1 Eureka 동작 프로세스

유레카의 동작 흐름

 

위의 사진은, 해당 포스트의 맨 위에 제시한 사진입니다. Eureka의 전체적인 

 

1. 서비스 실행 시점에, 각각의 마이크로 서비스는 Eureka Server에 서비스 ID와 URL 등의 정보를 등록한 후, 30초 간격으로 Heartbeat를 보내 자신의 가용성을 알림

 

2. Eureka Server 들은 'Peer to Peer' 관계 형성하여 서로의 상태 정보를 공유

 

3. Eureka Server로부터 읽어온 레지스트리 정보를 로컬에 캐싱하여 사용 (30초마다 주기적으로 갱신 / 새로 가져온 정보와 현재 캐싱된 정보의 차이를 가져오는 방식)

 

4. 이벤트 마이크로 서비스 8071로부터 Heartbeat가 일정 시간 이상 오지 않을 경우, Eureka Server는 레지스트리에서 해당 서비스를 제외

 

5. 회원 마이크로 서비스가 이벤트 마이크로 서비스를 호출할 때, 요청된 마이크로 서비스(서비스 ID)에서 현재 사용 가능한 서비스 목록을 제공하고, Ribbon을 사용하여 사용 가능한 이벤트 서비스들에게 요청을 분산

 

 


3. Eureka Server & Client 구축

3.1 Eureka Server 구현

마이크로 서비스들의 정보를 관리하는 Eureka Server를 구현해 보도록 하겠습니다.

 

3.1.1 build.gradle에 Eureka Server 의존성 추가

ext {
    set('springCloudVersion', "2023.0.3")
}

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

 

위와 같이 eureka-server 의존성 추가해 줍니다.

spring actuator도 유틸성 기능을 활용하기 위해 추가해 줬습니다.

 

3.1.2 Eureka Server 관련 application.yaml 설정

server:
  port: 8761

spring:
  application:
    name: discovery-server

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

  server:
    # 서버가 요청을 받기 전 대기할 초기 시간(ms) 
    # default 5분 : 실무에서는 보통 모든 서비스가 등록 되길 기다리기 위해 5분 후 정보를 공유
    # 개인 프로젝트인 만큼 빠른 등록을 위해 5ms로 설정 
    wait-time-in-ms-when-sync-empty: 5

management:
  endpoints:
    web:
      exposure:
        include: "*"
  • server.port : Eureka Server의 Port를 지정합니다.
  • spring.application.name : Eureka Server의 고유 ID(Name)를 지정합니다.
  • eureka.client.register-with-eureka : Eureka Server로 자신의 정보를 등록할지 결정합니다.
    • 현재는 Eureka Server 설정이므로 자기 자신을 등록할 필요는 없기 때문에 false로 설정했습니다.
  • eureka.client.fetch-registry : 다른 서비스들의 정보를 Eureka Server로부터 받아서 로컬 메모리에 캐싱할지 여부입니다.
    • 현재는 Eureka Server 설정이므로 자기 자신의 정보를 캐싱할 필요는 없기 때문에 false로 설정했습니다.
  • eureka.client.serviceUrl.defaultZone : Eureka 서버의 기본 주소를 지정합니다. defaultZone 속성에 설정된 URL은 클라이언트가 Eureka 서버와 통신할 때 사용할 기본 주소입니다.
  • eureka.server.wait-time-in-ms-when-sync-empty : 각 Service들의 등록을 위한 대기 시간입니다. 해당 시간 동안 대기한 후에 등록된 Service들의 정보를 공유합니다.
  • management.endpoints.web.exposure.include : Spring Actuator 관련 설정으로, Actuator의 어떤 API를 사용할 것인지 지정하는 설정입니다. 우선은 '*'으로 모든 API를 사용하도록 하겠습니다.


3.1.3 Eureka Server 활성화

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServerApplication {

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

}

 

실행 Application 위에 @EnableEurekaServer 어노테이션을 추가함으로써, Eureka Server 관련 구성이 적용되어 Eureka Server를 활성화할 수 있습니다.

 

위의 설정들을 모두 완료하고 Application을 실행한 후, localhost:8761(설정한 Eureka Server port)의 URI로 접속하면 Eureka Server 대시보드를 확인할 수 있습니다.

 

3.2 Eureka Client 구현

이제 각각의 Service에서 다른 서비스들의 정보를 얻기 위한 Eureka Client를 구현하도록 하겠습니다.

아래의 과정은 MSA의  각 서비스들에 모두 Eureka Client를 추가해 주면 됩니다.

 

3.2.1 build.gradle에 Eureka Client 의존성 추가

ext {
    set('springCloudVersion', "2023.0.0")
}

dependencies {
    // eureka-client 외의 서비스에 필요한 의존성들
    ...
    
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

 

위와 같이 eureka client 의존성을 추가해 줍니다.

spring actuator도 유틸성 기능을 활용하기 위해 추가해 줬습니다.

 

3.2.2 Eureka Client 관련 application.yaml 설정

server:
  port: 8011

spring:
  application:
    name: member-service

eureka:
  instance:
    prefer-ip-address: true
  client:
    register-with-eureka: true
    fetch-registry: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

management:
  endpoints:
    web:
      exposure:
        include: "*"

 

Eureka Server와 동일한 설정에 대한 설명은 생략하고, 차이 있는 부분에 대해서 살펴보겠습니다.

  • spring.application.name : Eureka 환경에서 통신할 서비스의 이름을 지정하는 옵션입니다.
    • Eureka 환경에서 통신을 할 때는 서비스의 IP:Port가 아닌, 고유 ID로 통신을 하게 됩니다.
    • 이때, 통신할 고유 ID를 지정하는 옵션입니다.
  • eureka.instance.prefer-ip-address : 서비스의 호스트 이름이 아닌, IP 주소를 Eureka Server에 등록할지 여부입니다.
    • 기본값은 false로, 해당 옵션을 true로 설정하지 않으면 Eureka Server에 각 서비스들이 내부적으로 호스트 이름으로 등록됩니다.
    • 서비스가 배포되는 환경에서 DNS가 존재한다면 호스트 이름을 할당받고 Eureka Server가 잘 등록할 수 있으므로 해당 옵션을 설정할 필요가 없습니다.
    • 지만, 컨테이너 기반의 배포 환경이라면 컨테이너가 DNS 엔트리가 없는 임의의 호스트 이름이 부여되기 때문에 해당 옵션을 false로 했을 때 Eureka Server가 해당 서비스의 호스트 이름 위치를 정상적으로 얻지 못합니다.
    • 따라서, 컨테이너 기반 배포라면 해당 옵션을 true로 하여 Eureka Server가 서비스를 IP 주소로 등록해서 찾도록 해야 합니다.
  • eureka.client.register-with-eureka : Eureka Server에 자기 자신을 등록할지의 여부이므로 true를 지정해 줬습니다.
  • eureka.client.fetch-registry : Eureka Server의 등록되어 있는 서비스들을 캐싱해 둘지의 여부이므로 true를 지정해 줬습니다.

3.2.3 Eureka Client 활성화

@EnableDiscoveryClient
@SpringBootApplication
public class MemberServiceApplication {

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

}

 

실행 Application 위에 @EnableDiscoveryClient 어노테이션을 추가함으로써, Eureka Client 관련 구성이 적용되어

Eureka Client를 활성화할 수 있습니다.

 

 


참고

https://cloud.spring.io/spring-cloud-netflix/reference/html/#service-discovery-eureka-clients

 

Spring Cloud Netflix

This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common pat

cloud.spring.io

 

 

https://assu10.github.io/dev/2020/08/16/spring-cloud-eureka/#1-service-registry--discovery-%EC%84%9C%EB%B9%84%EC%8A%A4-%EB%93%B1%EB%A1%9D-%EB%B0%8F-%EB%B0%9C%EA%B2%AC

 

Spring Cloud - Spring Cloud Eureka

이 포스트는 MSA 를 보다 편하게 도입할 수 있도록 해주는 스프링 클라우드 프로젝트 중 Spring Cloud Eureka 에 대해 기술한다. 관련 소스는 github/assu10 를 참고 바란다.

assu10.github.io

 

 

https://ksh-coding.tistory.com/137#2.%20Server-Side%20Discovery%20%2F%20Client-Side%20Discovery-1

 

[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (3) Service Discovery 패턴 적용하기(feat. Spring Cloud Eureka)

앞서 Chapter 1에서 MSA 도입 시 고려할 점에서 'Service Discovery 패턴'이라는 개념이 등장했었습니다. 이번 챕터에서는 Service Discovery 패턴에 대해 알아보고 해당 패턴을 구현한 Spring Cloud Netflix의 Eureka

ksh-coding.tistory.com

 

'Spring > Spring Cloud Eureka' 카테고리의 다른 글

Spring Cloud Eureka 상세 설정  (0) 2024.11.07