이 글은 인프런 Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) 강의를 들은 후에 정리한 글입니다.
(https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard)
이 글에서 설명되는 내용들은 모두 실제 강의와 다른 Spring Boot 3.1.2 버전입니다.
Spring Cloud Netflix Eureka
Service Discovery: 외부의 서비스들이 Microservice를 검색하기 위해 사용하는 것, 일종의 전화번호부 역할을 함
서비스의 등록과 검색 기능을 제공하는 기능을 Eureka를 사용하여 제공
Eureka Service Discovery - 프로젝트 생성
discoveryservice라는 이름을 가지는 새로운 프로젝트를 생성한다. (Java 17, Spring Boot 3.1.2)
application.yml에 다음과 같이 등록한다.
# application.yml
server:
port: 8761
spring:
application:
name: discoveryservice
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:port 속성에서는 Spring Boot 애플리케이션이 실행될 포트를 설정한다. 여기서는 포트 8761에서 애플리케이션이 실행되게 설정을 한 것이다.
spring:application:name 속성은 Spring Boot 애플리케이션의 이름을 설정하는 것으로 여기에서는 "discoveryservice"로 설정한다.
eureka:client는 Eureka Discovery Client의 동작을 구성한다. 이를 통해 애플리케이션이 서비스 검색 및 등록을 위해 Eureka 서버에 자신을 등록할 수 있다.
register-with-eureka: false는 이 서비스가 어떤 Eureka 서버에도 자신을 등록하지 않을 것임을 나타낸다.
fetch-registry: false는 이 서비스가 다른 Eureka 서버로부터 레지스트리 정보를 가져오지 않을 것임을 나타낸다.
다음으로 main 함수가 있는 DiscoveryserviceApplication.java에 다음과 같이 어노테이션 하나를 추가한다.
// DiscoveryserviceApplication.java
@SpringBootApplication
@EnableEurekaServer // 추가된 어노테이션
public class DiscoveryserviceApplication {
public static void main(String[] args) {
SpringApplication.run(DiscoveryserviceApplication.class, args);
}
}
@EnableEurekaServer: 이 어노테이션은 해당 애플리케이션이 다른 마이크로서비스들의 등록 및 검색을 관리하는 Eureka Discovery 서버로서 동작하도록 활성화시킨다.
실제로 127.0.0.1:8761에 접속해 보면 다음과 같은 실행 화면을 볼 수 있다.
User Service - 프로젝트 생성
user-service라는 이름을 가지는 새로운 프로젝트를 생성한다. (Java 17, Spring Boot 3.1.2)
application.yml에 다음과 같이 등록한다.
# application.yml
server:
port: 9001
spring:
application:
name: user-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
default-zone: http://127.0.0.1:8761/eureka
이전과 달라진 부분만을 설명해 보겠다.
eureka:client는 Eureka Discovery Client의 동작을 구성한다. 이를 통해 애플리케이션이 서비스 검색 및 등록을 위해 Eureka 서버에 자신을 등록할 수 있다.
register-with-eureka: true는 이 클라이언트가 Eureka 서버에 자신을 등록할 것임을 나타낸다.
fetch-registry: true는 이 클라이언트가 Eureka 서버로부터 레지스트리 정보를 가져올 것임을 나타낸다.
service-url 섹션은 Eureka 서버의 URL을 설정한다. 여기서는 기본(default) zone으로 http://127.0.0.1:8761/eureka를 사용하며 이것은 Eureka 서버의 주소를 나타낸다.
다음으로 main 함수가 있는 UserServiceApplication.java에 다음과 같이 어노테이션 하나를 추가한다.
// UserServiceApplication.java
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
@EnabledDiscoveryClient: 애플리케이션을 서비스 디스커버리 클라이언트로 등록할 때 사용한다.
이제 실행 후 유레카 서버에 접속해 보면 아래와 같이 USER-SERVICE가 추가된 것을 확인할 수 있다.
User Service - 등록
위에서 추가된 USER-SERVICE 말고 또 다른 USER-SERVICE를 추가해 볼 것이다.
먼저 IntelliJ 우측 상단의 실행 버튼 옆의 클래스 이름을 누르면 내려오는 드롭 다운 선택창에서 Edit Configuration을 클릭한다.
UserServiceApplication을 선택한 상태에서 복사 버튼을 눌러 UserServiceApplication-2를 생성한다.
드롭 다운 선택창을 통해 둘 모두를 실행한다.
그러면 위와 같은 오류창을 보게 될 텐데 이는 9001 포트를 둘 다 사용하려고 하기 때문이다.
Modify options에서 Add VM options 선택하여 다음과 같이 추가하면 UserServiceApplication-2가 9002 포트에서 실행되게 설정할 수 있다.
설정 후 다시 실행하면 아래와 같이 둘 다 정상 작동함을 알 수 있다.
또 다른 실행 방법도 사용해 보겠다.
IDE의 터미널에서 현재 프로젝트의 경로에 위치한 뒤 다음의 명령어를 입력한다.
mvn spring-boot:run '-Dspring-boot.run.jvmArguments= -Dserver.port=9003'
강의에서의 명령어와 살짝 환경 변수 부분이 다르니 주의하자.
실행이 잘 되었는지 브라우저에서 확인해 보면 다음과 같이 잘 실행되었음을 확인할 수 있다.
마지막으로 4번째 인스턴스를 실행해 보자.
cmd에 접속해서 다음 명령어를 입력한다.
mvn clean
mvn compile package
위의 과정을 통해 현재 경로의 target 하위 폴더에 user-service-0.0.1-SNAPSHOT.jar 파일이 생성되었는지 확인 후 아래 명령어를 통해 새로운 인스턴스를 포트 9004에서 실행한다.
java -jar "-Dserver.port=9004" ./target/user-service-0.0.1-SNAPSHOP.jar
브라우저에서 확인해 보면 4개의 인스턴스가 실행 중임을 확인할 수 있다.
이후 정상적으로 모든 인스턴스를 종료한다.
User Service - Load Balancer
지금까지는 포트 번호를 인스턴스를 실행할 때마다 하나하나 지정해 주는 방식으로 진행하였는데, 이는 너무 귀찮은 작업이다.
그래서 랜덤으로 포트 번호를 부여하는 방법을 사용해보고자 한다.
application.yml에서 server:port 속성을 기존의 9001에서 0으로 변경한다.
그 이후 실행해 보면
아래처럼 랜덤으로 지정된 50896 포트에서 실행됨을 알 수 있다.
터미널에서 mvn spring-boot:run 명령을 입력하여 또 다른 랜덤 포트에서 실행되는지 확인해 보자.
51126이라는 랜덤으로 지정된 포트에서 실행됨을 알 수 있다.
하지만 브라우저에서 확인해 보면 두 개의 인스턴스가 실행 중인 것으로 나오는 것이 아닌, 하나의 인스턴스만 존재하는 것처럼 보인다. 왜냐하면 application.yml에 지정된 정적인 포트값 그 자체만을 출력해 주는 방식이기 때문이다.
이를 해결하기 위해서 application.yml에 새로운 내용을 추가해 주자.
# application.yml
...
eureka:
instance:
instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
client:
...
새로운 내용을 추가 후 다시 두 인스턴스를 실행하고, 브라우저에서 확인해 보면 아래와 같이 2개의 인스턴스가 나타남을 확인할 수 있다.
위처럼 USER-SERVICE에 대한 자동 포트 부여를 통해 여러 인스턴스를 귀찮게 포트번호를 부여할 필요 없이 생성할 수 있게 됨으로써 편하게 개발자들이 작업할 수 있다.
이렇게 Spring Boot와 Spring Cloud를 사용하여 로드 밸런싱을 쉽게 구현할 수 있다.