Service Discovery
Service Discovery
이후에 실습할 때도 적용을 해보겠지만, MSA 환경에서는 유연한 scale-out을 위해 IP나 Port 정보를 고정해서 사용하지 않고 유동적으로 사용하게 된다
MSA를 위해 여러 대의 서버를 동시에 띄운다고 하면, 각 서버별로 할당된 포트번호가 서로 다르거나 서로 다른 PC에서 서버를 띄워야 할 것이다. 우리는 하나의 PC를 통해 여러 서비스를 띄울 것이기 때문에, 이러한 서비스마다 주소를 관리해주는 Service Discovery 매쉬 서비스를 만들어야 한다.
Service Discovery는 외부의 클라이언트나 서비스에서 마이크로 서비스를 검색할 때, 각 마이크로 서비스가 어떤 주소에 매핑 되어있는지를 알려주는 기능을 한다. 일종의 전화번호부라고 볼 수 있다.
마이크로 서비스를 Service Discovery 서버에 등록하는 작업을 먼저 수행해야한다. 클라이언트에서는 자신이 필요한 정보를 로드밸런서나 API Gateway에 전달하면, Service Discovery를 통해 해당 요청에 맞는 서비스가 어디있는지 반환하고 이를 통해 클라이언트는 서비스에 접근할 수 있는 것이다.
Spring Cloud Netflix Eureka
Netflix에서 개발하여 Spring 재단에 기부하여 등록된 Service Discovery 기능을 지원하는 프로젝트이다. 외부에서 마이크로 서비스 위치를 찾아주는 Service Discovery 기능과, 각각의 마이크로 서비스가 자신의 IP와 Port 정보를 등록해두는 Service Registry 기능을 지원한다.
Service Discovery 서버 생성하기
buildscript {
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.5.RELEASE")
}
}
apply plugin: "spring-boot"
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.RELEASE"
}
}
XML
복사
위와 같이 라이브러리 Dependency를 추가한다.
server:
port: 8761
spring:
application:
name: discovery-service
eureka:
client:
registerWithEureka: false
fetchRegistry: false
YAML
복사
그 후 application.yml에 이처럼 설정을 추가한다.
•
server.port를 통해서 Discovery Service가 사용할 포트 번호를 지정한다.
•
spring.application.name으로 서비스 이름을 지정한다.
•
eureka.client의 registerWithEureka와 fetchRegistry를 통해서 Discovery Service 서버 자신을 서비스로 등록하는 것을 막는다.
@SpringBootApplication
@EnableEurekaServer
public class DiscoveryserviceApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryserviceApplication.class, args);
}
}
Java
복사
그 후 애플리케이션 메인에 @EnableEurekaServer 애노테이션을 추가하여, 애플리케이션이 Discovery Service로 동작하도록 설정하면 끝난다.
이후 애플리케이션을 실행시킨 이후 호스트 주소로 접속해보면 이와 같이 서비스 이름, 등록된 서비스들, 서비스 정보 등을 확인할 수 있다.
서비스 등록하기
우리가 작성할 마이크로 서비스를 Discovery Service에 등록하는 것은 간단하다.
ext {
set('springCloudVersion', "2023.0.0")
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
...
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
XML
복사
이와 같이 라이브러리 의존성을 추가한 후,
server:
port: 9001
spring:
application:
name: user-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
YAML
복사
이처럼 application.yml에 설정 사항을 추가한다.
(포트 설정과 서비스 이름 설정 부분은 위와 동일하니 생략)
•
eureka.client의 registerWithEureka와 fetchRegistry를 통해서 이 서비스가 Discovery Service에 등록될 것임을 명시한다.
•
eureka.client.service-url.defaultZone으로 우리가 작성한 Discovery Service의 유레카 서버 호스트 주소를 넣어준다.
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
Java
복사
이와 같이 애플리케이션의 메인에 @EnableDiscoveryClient 애노테이션을 추가해주면 Discovery Service에 등록된다.
아까의 Discovery Service에 접속해보면, 이와 같이 서비스가 등록되어 있는 것을 볼 수 있다.
서비스 동적 포트 번호 설정하기
위에서도 언급했듯이, MSA는 상황에 따라 유연하게 서비스를 스케일 아웃하여 확장할 수 있어야 한다. 이를 구현하려면 우리가 매 서비스를 실행 시마다 yml 파일을 변경하거나 -Dserver.port=xxxx와 같이 별도로 포트 번호를 지정하여 서비스를 실행시켜야한다.
하지만 매번 서비스를 켤 때마다 포트 번호를 지정하는 일은 비효율적이고 번거로운 일이다. 때문에 우리는 포트 번호를 동적으로 사용할 것이다.
server:
port: 0
YAML
복사
이처럼 application.yml 파일에 포트 번호 지정을 0으로 하게 되면, 애플리케이션을 실행할 때 Spring에서 남는 포트 중 하나를 선택하여 할당하게 된다.
애플리케이션 실행 로그를 보면, 0번으로 지정했지만 이와 같이 임의의 빈 포트를 지정하여 서비스가 실행되는 것을 확인할 수 있다.
이와 같이 Discovery Service에서도 0번 포트로 바뀌어 등록된 것을 확인할 수 있다.
하지만 여기에는 문제가 한 가지 있다. 우리의 원래 의도에 맞게 0번 포트로 동적 지정하여 서비스를 2개 이상 띄워보자.
이처럼 서비스를 2개 이상 실행시켰음에도 Discovery Service에서는 하나의 서비스만 등록된 것처럼 보이게 된다.
eureka:
instance:
instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
YAML
복사
이를 해결하기 위해 application.yml 파일에 위와 같이 설정을 추가하자.
이는 Discovery에 Service를 등록할 때, 등록할 instance의 id를 지정하는 설정이다. instance_id에 랜덤 UUID를 추가하여 매 서비스마다 다른 이름을 지정하도록 한다.
그러면 이처럼 서로 다른 이름을 가진 인스턴스로 인식되어, Discovery Service에서 여러 개의 인스턴스가 전부 보이게 된다. 해당 링크로 들어가보면 IP와 Port 번호가 잘 등록이 되어있는 것을 확인할 수 있다.