Netflix Eureka
Eureka ??
netflix에서 개발한 MSA의
Service Discoveryservice
서비스들을 동적으로 관리하고, 상태를 확인할 수 있다.
Eureka Example
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.github.mj-youn</groupId>
<artifactId>Spring-Netflix-Eureka</artifactId>
<version>0.1</version>
<name>Spring-Netflix-Eureka</name>
<description>Eureka</description>
<properties>
<java.version>1.8</java.version>
</properties>
<!-- spring cloud library를 사용하기 위한 설정 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring-boot-starter-web과 같은 web 관련 library가 필요없음 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.java
package io.github.mjyoun;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer // eureka server로 사용하기 위한 설정
@SpringBootApplication
public class SpringNetflixEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringNetflixEurekaApplication.class, args);
}
}
application.yml
spring:
application:
name: eureka
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: "http://127.0.0.1:8761/eureka"
server:
wait-time-in-ms-when-sync-empty: 0
실제 적용 예시
- LG U+ 관련 업무를 진행하면서 MSA 구조를 적용시키면 좋을만한 프로젝트를 맡게 되어, spring cloud를 사용한 MSA 구조를 가지고 설계하여 개발한 적이 있음.
Service Discovery (Eureka)
spring:
profiles:
application:
name: .........
server:
address: 0.0.0.0
port: 18082
logging:
config: ./config/log4j2.yml
eureka:
client:
register-with-eureka: false # 자기 자신을 다른 eureka server에 등록을 막는다.
fetch-registry: false # client 서비스가 eureka 서버로 받는 서비스 리스트 정보를 local에 caching 할지 여부
service-url:
defaultZone: http://localhost:${server.port}/eureka
server:
eviction-interval-timer-in-ms: 1000 # client가 종료된 후 서버 목록에서 1000ms 후 제거
wait-time-in-ms-when-sync-empty: 0
enable-self-preservation: true
response-cache-update-interval-ms: 5000 # client에게 전달할 서버 목록을 유지하는 시간
- 실제 소스상의 구현은 없고, 위와 같이 설정만 작성하여 동작시켰다.
- 요구사항중 하나로 micro-service가 수시로 on/off될 수 있기 때문에 service 목록을 cash로 유지하지 않고, 수시로 불러와야 했음.
- 관련된 설절잉
eureka.server.~에 작성되어 있음. 정확한 설명은 검색이 필요함.
API Gateway (Zuul)
pom.xml
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- ************** -->
<!-- begin: logging / log4j2 -->
<!-- https://mvnrepository.com/artifact/com.lmax/disruptor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.6</version>
</dependency>
<!-- end: logging -->
<!-- ************** -->
<!-- ************** -->
<!-- begin: jackson (; for parse logging yml file) -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<!-- end: jackson -->
<!-- ************** -->
</dependencies>
...
application.yml
...
eureka:
instance:
prefer-ip-address: true # Eureka 등록시 사용한 IP를 가지고 Eureka에서 호출할 수 있게 함
client:
service-url:
defaultZone: "http://127.0.0.1:18082/eureka"
registry-fetch-interval-seconds: 5
# zuul 설정
zuul:
ignoreSecurityHeaders: false # true면 spring security의 Authorization 값을 무시(제외)한다.
sensitiveHeaders: # header에서 제외하는 목록. 여기에 값을 추가하면 제외하는 값이다. (목록 형태)
routes:
twamp-service:
path: /ts/**
strip-prefix: true # 매칭되는 값(/ts)을 제외하고 보낸다. ex> /ts/start --> /start
tgw-rapidping:
path: /ns/**
strip-prefix: true
# actuator
management:
endpoints:
web:
exposure:
include: "*" # actuator에서 지원하는 모든 관리 port를 연다
endpoints:
routes:
enabled: false # endpoint 변경을 막는다.
# hystrix 설정
hystrix:
command:
default: # 모든 서버에 동일하게 적용. 필요시 서비스 이름으로 따로 정하면 됨
execution:
isolation:
thread:
timeoutInMilliseconds: 10000
# ribbon 설정
ribbon:
ConnectTimeout: 5000
ReadTimeout: 30000
eureka:
enabled: true
ServerListRefreshInterval: 1000
...
application.java
package kr.co.lguplus.tgw.api_gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy // zuul 설정
@EnableDiscoveryClient // eureka client 설정
@SpringBootApplication
public class APIGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(APIGatewayApplication.class, args);
}
}
- zuul server 역시 java 소스는 없이 설정만으로 서버를 구동시켰다.
ribbon과hystrix역시 spring cloud에 존재하는 MSA 서비스 중에 하나로, 나중에 기회가 되면 포스팅하는 걸로.. (아직은 공부가 미흡함..)actuator를 사용하기 위해 관련 library를pom.xml에 추가
Micro service
application.java
...
@EnableDiscoveryClient
@SpringBootApplication
public class TwampServiceApplication {
...
application.yml
...
# actuator
management:
endpoints:
web:
exposure:
include: "*" # actuator에서 지원하는 모든 관리 port를 연다
eureka:
instance:
prefer-ip-address: true # Eureka 등록시 사용한 IP를 가지고 Eureka에서 호출할 수 있게 함
instance-id: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}} # random instance-id로 선언
client:
service-url:
defaultZone: "http://127.0.0.1:18082/eureka" # eureka 접속 URL
...
- 실제 API gateway를 통해 호출되는 micro-service는 두 종류지만, 본인이 직접개발했던 내용만을 포함시킴.
service discovery서버와api gateway서버가 물리적으로 한 서버에 있고, micro-service가 물리적으로 다른 서버에 있었기 때문에, micro-service가service discovery에 등록될 때 자기 자신의 IP를 가지고 등록되어야하고 호출도 그 IP를 가지고 해야하는 이슈가 있었음.eureka.instance.prefer-ip-address설정으로 해결했으나, 최근 다른 프로젝트의 MSA를 봐주던 중 설정을 위와 같이해도 nic이 여러 개일 경우, 첫번째 nic의 ip를 가져와서 호출하는 현상을 발견하였다… 운이 좋아서 해결이 됬다고 봐야할 듯하다. nic이 여러 개일 경우에 대한 해결 법은 추후 확인이 필요하다.