마이크로서비스 구조에서 서비스 디스커버리를 위해 Spring Cloud Netflix Eureka를 도입했다. Gateway가 각 서비스의 IP를 직접 하드코딩하는 게 아니라, Eureka를 통해 동적으로 서비스를 발견하고 로드밸런싱까지 가능하게 하는 게 목표였다.
전체 구조
1
2
3
4
[platform-data-api] ──등록──▶ [Eureka Server :8761]
[platform-be-gateway] ──조회──▶ [Eureka Server :8761]
│
lb://data-api 로 동적 라우팅
서비스들이 Eureka에 자신을 등록하면, Gateway는 Eureka에서 서비스 목록을 조회해서 자동으로 라우팅한다. 나중에 VM이 추가되더라도 새 인스턴스가 Eureka에 등록만 하면 자동으로 로드밸런싱 대상에 포함된다.
build.gradle
Spring Boot 3.0.11, Spring Cloud 2022.0.4 기준이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
plugins {
id 'java'
id 'org.springframework.boot' version '3.0.11'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.eureka'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', '2022.0.4')
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
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}"
}
}
jar {
enabled = false
}
주의: io.spring.dependency-management 버전은 반드시 1.1.7 이상으로 맞춰야 한다.
Gradle 9.x에서 1.1.3 버전을 사용하면 아래 에러가 발생한다.
1
NoSuchMethodError: LenientConfiguration.getArtifacts(Ljava/util/Set;)Ljava/util/Set;
메인 클래스
1
2
3
4
5
6
7
@EnableEurekaServer
@SpringBootApplication
public class PlatformBeEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformBeEurekaApplication.class, args);
}
}
@EnableEurekaServer 하나만 붙이면 된다.
application-dev.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 8761
spring:
application:
name: platform-be-eureka
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false # 서버 자신은 Eureka에 등록하지 않음
fetch-registry: false # 다른 서비스 목록을 가져오지 않음
service-url:
defaultZone: http://localhost:8761/eureka/
server:
wait-time-in-ms-when-sync-empty: 0 # 시작 시 불필요한 대기 제거
enable-self-preservation: false # dev: 서비스 수가 적어 임계값 미달 경고 방지
application-prd.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 8761
spring:
application:
name: platform-be-eureka
eureka:
instance:
hostname: ${EUREKA_HOSTNAME:localhost}
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${EUREKA_HOSTNAME:localhost}:8761/eureka/
server:
wait-time-in-ms-when-sync-empty: 0
enable-self-preservation: false
prd에서도 서비스 수가 많지 않으면 self-preservation을 꺼두는 게 낫다. 켜두면 아래 경고가 계속 뜬다.
1
2
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT.
RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
Self-Preservation Mode란
Eureka는 등록된 인스턴스 수의 85% 이상이 30초마다 heartbeat를 보내야 정상으로 판단한다.
1
임계값 = 등록된 인스턴스 수 × 2 × 0.85
서비스가 1~2개뿐이면 분당 heartbeat 횟수가 임계값에 못 미쳐서 자기 보존 모드에 진입한다. 이 모드에서는 서비스가 응답 없어도 강제로 제거하지 않는다. 네트워크 이슈로 인한 대량 해제를 방지하기 위한 안전장치인데, dev 환경에서는 그냥 꺼두면 된다.
클라이언트 서비스 등록 (data-api 예시)
build.gradle
1
2
// Eureka Client
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:4.0.3'
application-dev.yml
1
2
3
4
5
6
7
8
9
10
spring:
application:
name: data-api # Eureka 등록 이름 = Gateway 라우팅 경로
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
spring.application.name이 Eureka에 등록되는 서비스 ID가 된다. Gateway는 이 이름으로 라우팅한다.
@EnableDiscoveryClient 어노테이션은 Spring Boot 3 + Spring Cloud 2022 조합에서는 붙이지 않아도 자동으로 등록된다.
확인
Eureka 서버 기동 후 http://localhost:8761 접속하면 대시보드에서 등록된 서비스를 확인할 수 있다.
1
2
3
Instances currently registered with Eureka
Application AMIs Availability Zones Status
DATA-API n/a (1) UP (1) - ...
서비스 이름은 대문자로 표시된다. Gateway의 discovery locator에서 lower-case-service-id: true 설정을 하면 /data-api/** 경로로 라우팅된다.
실행 순서
- Eureka Server 먼저 기동 →
http://localhost:8761대시보드 확인 - platform-data-api 기동 → 대시보드에
DATA-API등록 확인 - platform-be-gateway 기동 →
PLATFORM-BE-GATEWAY등록 확인