MSA

[MSA] Part 4. Service 등록 (User)

cwchoiit 2023. 10. 6. 15:19
728x90
반응형
SMALL
728x90
반응형
SMALL

이제 Eureka Server를 만들었으니 하나씩 비즈니스 서비스를 만들어보자. 그 중 첫 번째는 User Service.

똑같이 IntelliJ로 Spring Initializr를 사용하자.

 

User Service 생성

 

위처럼 설정했고 Next

 

Dependencies 설정하는 부분이 Eureka보다 더 많은데 하나씩 설정해보자.  

필요한 Dependencies

  • Spring Boot DevTools
  • Lombok
  • Spring Web
  • Eureka Discovery Client

위처럼 다 체크했으면 Create해서 프로젝트를 생성

 

 

pom.xml

역시 마찬가지로 가장 먼저 확인할 파일은 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 https://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>3.1.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>user-service</artifactId>
    <version>0.0.1</version>
    <name>user-service</name>
    <description>user-service</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2022.0.4</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</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-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

추가한 dependencies들을 모두 확인했으면 메인 클래스로 넘어가자.

 

 

UserServiceApplication

package com.example.userservice;

import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {

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

이 파일에서 추가할 내용은 @EnableDiscoveryClient 어노테이션이다. 즉, 이 서버를 Service discovery의 Client로 등록하겠다는 어노테이션.

 

 

application.yml

마찬가지로 application.properties파일을 application.yml로 바꾸고 시작하자. 추가할 내용은 다음과 같다.

server:
  port: 9001

spring:
  application:
    name: user-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

이 UserService의 application.yml 파일은 많은 업데이트가 있을 예정이다. 일단 최초 시작은 이렇게 시작한다.

역시나 server.port, spring.application.name을 설정해준다.

 

eureka.client.register-with-eureka: true로 설정하면 eureka에 서비스로 등록될 서버라는 의미다.

eureka.client.fetch-registry:true로 설정하면 eureka server로부터 갱신되는 서비스 정보들을 지속적으로 받겠다는 의미이다.

eureka.client.service-url.defaultZone: http://127.0.0.1:8761/eureka eureka server 정보를 기입하는 부분이다.

 

 

UserService 실행

이제 User Service를 실행해보자. 다음과 같은 로그가 출력되면 된다.

그리고 이렇게 정상 실행이 됐으면 Eureka server를 열어보자. User Service가 등록된 모습을 확인할 수 있다.

해당 라인에서 우측 Status 칼럼에 보면 UP(1)이라고 보인다. 한 개의 인스턴스가 띄워져 있는 상태란 의미이다. 한번 여러개를 띄워보자. 같은 서비스라 할지라도 포트를 나누어 더 많은 인스턴스를 띄울 수 있다. 그리고 이렇게 여러개의 인스턴스를 띄워서 부하 분산 처리가 가능해진다. 

 

 

Start Multiple Instance

기본적으로 IntelliJ에서 상단 아이콘바에 실행버튼을 클릭하면 서버가 실행되는데 이 외 여러 방법으로 실행이 가능하다. 그리고 그 방법을 통해 여러개를 띄워보자.

 

첫번째는 Run/Debug Configurations이다.

사진처럼 실행할 애플리케이션 선택창을 클릭해서 Edit Configurations를 누르면 아래처럼 Run/Debug Configurations 창이 하나 노출된다. 

위 창에서 빨간색 네모칸으로 표시한 "Copy configurations" 버튼을 누르면 현재 실행하고 있는 애플리케이션 구성과 동일한 또 다른 인스턴스의 애플리케이션 구성을 만들 수 있다. 그렇게 하나 추가하면 다른 인스턴스로 또 하나를 실행할 수 있다. 근데 그대로 복사해서 실행하면 같은 포트를 사용할 거기 때문에 포트 충돌 에러가 발생할것이다. 그래서 포트를 변경해줘야 한다. 다음 사진을 보자.

실행할 때 VM option을 추가해줄 수 있다. VM option에 application.yml 파일에 설정한 server.port값을 위 사진처럼 변경한다.

설정 후 Apply > OK

이렇게 새로운 Configurations이 생겼고 역시 실행 버튼 또한 활성 상태가 된다. 이 인스턴스도 실행해보자.

정상 실행이 되었고 9092 포트로 실행됐다는 로그가 보인다. 이 인스턴스 역시 Eureka Server에 등록될 것인데 한번 Eureka Server를 띄워보자. Status를 보면 UP(2) 라는 표시가 보인다.

2개의 유저 서비스가 띄워져있음을 그리고 그 서비스가 모두 같은 Eureka Server에 등록되어 있음을 확인할 수 있다.  

 

 

두 번째는 Maven을 이용하는 방법이다.

pom.xml파일이 있는 경로에서 다음 명령어를 입력한다.

mvn spring-boot:run -Dspring-boot.run.jvmArguments='-Dserver.port=9003'

마찬가지로 정상적으로 실행된 로그가 찍힌다.

역시 Eureka Server에도 등록된 모습까지 확인할 수 있다.

 

 

세 번째는 패키징한 Jar파일을 실행한다.

이 또한 pom.xml파일이 있는 경로에서 다음 명령어를 입력한다.

mvn clean compile package -DskipTests=true

Maven으로 빌드 후 패키징하는 명령어인데 clean은 기존에 패키징했던 것들을 전부 말끔히 지우고, compile은 빌드를 한다. package는 말 그대로 패키징을 하는 것이고 -DskipTests=true는 프로젝트 내 테스트 파일이 있을 때 테스트를 스킵한다는 의미이다.

 

그럼 프로젝트 루트 경로에 target이라는 폴더가 생기고 해당 폴더 안에 .jar파일이 생긴다.

.jar파일의 이름은 pom.xml파일에서 설정한 값으로 그대로 만들어지는데, 앞 부분은 <name></name>안에 설정된 값이고 뒷 부분은 <version></version>안에 설정된 값이다. 

 

이 jar파일을 실행하면 된다.

java -jar -Dserver.port=9004 ./target/tistory-user-service-0.0.1-SNAPSHOT.jar

마찬가지로 서비스는 정상적으로 띄워진다.

 

 

⭐️ Random port generated

위 작업들은 모두 다 너무 귀찮다. 일일이 포트번호를 변경해주는 것은 개발자 경험을 떨어뜨린다. 그래서 어떤 포트던 상관없이 임의로 포트를 할당해준다. 

application.yml 파일에서 server.port 값을 0 으로 설정하면 사용하고 있지 않은 포트를 랜덤으로 할당한다.

server:
  port: 0
spring:
  application:
    name: user-service

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

이렇게 설정을 변경하고 실행해보자. 잡힌 포트번호를 출력해주는 로그를 잘 봐야한다.

실행해보면 포트를 49318이라는 포트로 잡은 것을 확인할 수 있다. Eureka Server에서도 확인해보자.

여기서 0번 포트라고 표시되어 있다. 실제로 포트를 0번으로 잡은건 아니고 우리가 설정한 0이라는 값이 그대로 출력된 모습인데 이 링크를 실제 클릭해보면 같은 49318로 연결됨을 확인할 수 있다.

 

 

하나 더 띄워보자. 터미널에서 실행한 방법 그대로 실행해보는데 이번엔 포트를 명시하지 않고 실행해보자.

mvn spring-boot:run

역시나 임의의 포트로 자동 할당된 모습이다. 이렇게 일일이 포트를 직접 명시하는 게 아닌 랜덤 포트를 할당받는 방법으로 인스턴스를 여러개 기동시킬 수 있다. 

 

근데 이대로는 문제가 있다. 어떤 문제냐면 Eureka Server를 다시 보면 분명 인스턴스를 두 개 띄웠지만 하나만 보여진다.

이는 왜일까? Eureka Server에서 서비스를 등록할 때 서비스를 표시하는 방법에서 원인이 있다.

서비스를 등록할 때 서비스 표현 방법을 59.29.234.174:user-service:0 이렇게 표현 하는데 이는 서비스가 띄워진 IP:서비스의 이름:서비스의 포트이다. 서비스의 이름과 서비스의 포트는 application.yml파일에서 설정한 spring.application.name값과 server.port값인데 이 두개의 차이가 인스턴스별 존재하지 않기 때문에 아무리 많이 몇 개를 띄우더라도 Eureka Server는 하나만을 표시할 것이다. 

 

이를 수정하기 위해, eureka.instance.instance-id 값을 부여해야한다.

server:
  port: 0
spring:
  application:
    name: user-service

eureka:
  instance:
    instance-id: ${spring.cloud.client.hostname}:${spring.application.instance_id:${random.value}}
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka

이렇게 application.yml파일을 수정 후 다시 인스턴스 두 개를 실행한 뒤 Eureka Server를 다시 확인해보자.

이제는 서버의 IP뒤에 알수없는 랜덤값이 표시된 것을 확인할 수 있고 띄운 인스턴스 개수만큼 표시됨을 확인할 수 있다. 이렇게 여러개의 인스턴스를 띄우고 같은 Eureka Server에 등록하는 방법을 알아봤다. 이렇게 여러개의 인스턴스를 띄워서 서비스를 운영하면 유저가 요청을 했을 때 해당 요청을 처리할 수 있는 인스턴스들 중 남는(놀고있는) 인스턴스를 찾아 그 인스턴스에게 요청을 할당하는 Load Balancing기술을 사용할 수 있게 된다.

 

 

User Service 내 API 및 비즈니스 로직을 구현하기 전 API Cloud Gateway를 구현해보자.

728x90
반응형
LIST

'MSA' 카테고리의 다른 글

[MSA] Part 6. Gateway Filter  (2) 2023.10.10
[MSA] Part 5. API Gateway  (0) 2023.10.06
[MSA] Part 3. Spring Cloud Netflix Eureka  (0) 2023.10.06
[MSA] Part 2. Spring Cloud란?  (0) 2023.10.06
[MSA] Part 1. Spring Microservices Architecture  (0) 2023.10.05