본문 바로가기
DDD&MSA

[MSA] Micro Service Architecture(MSA) 시작하기 - Eureka Server & Client

by 덩라 2023. 9. 10.

1. 모놀리식 vs MSA

MSA 를 공부하게 되면, 자연스럽게 모놀리식 이라는 개념 또한 접하게 됩니다. 

모놀리식이란, 여러 도메인을 하나의 아키텍처에 구성해놓은 서비스로, 과거에 흔히 개발됐던 하나의 프로젝트에 애플리케이션 전체가 구현된 형태를 뜻합니다. 그에 반대되는 MSA는 여러 작은 서비스들이 함께 동작하는 서비스로, 각자의 독립적인 서비스가 외부통신을 통해 데이터를 주고 받고, 시스템에 요구되는 처리를 수행하는 형태를 뜻합니다.

모놀리식과 대비되는 MSA의 장점은 아래와 같습니다.

  1. 각각의 서비스에 최적의 아키텍처를 설계할 수 있다.
  2. 하나의 서비스의 장애가 전체 서비스에 영향을 주지 않는다.

MSA 를 구성하는 작은 서비스 하나를 마이크로 서비스 라고 부르며, 각 마이크로 서비스마다 도메인에 맞는 최적의 아키텍처를 설계할 수 있습니다. 예를 들어, 주문과 같이 금액과 관련된 도메인을 설계하는 경우, 데이터의 정합성을 보장하기 위해 RDB 를 사용하면서, 상품과 같이 조회가 많이 발생하는 도메인에 대해서는 조회에 좀 더 성능이 좋은 NoSQL을 적용할 수 도 있고, 상품 도메인은 Node.js로 개발하고 주문 도메인은 Java/Spring 으로 개발하는 등, 각각의 마이크로 서비스들에게 최적화된 기술을 적용해서 개발할 수 있습니다.

 

또한, 모놀리식의 경우 어느 한 부분에서 장애가 발생하면, 그 장애가 애플리케이션 전체에 영향을 주는 반면, MSA의 경우 하나의 마이크로 서비스에서 장애가 발생한다 해도, 해당 마이크로 서비스와 직접적인 연관이 없는 다른 서비스는 장애의 영향을 받지 않는다는 점도 모놀리식과 비교되는 MSA 구조의 장점이라고 볼 수 있습니다.

 

하지만, MSA는 모놀리식 구조보다 복잡한 시스템 구조를 가지게 되고, 이러한 구조로 인해 개발 난이도가 높고, 시스템의 관리포인트가 많아지는 단점을 가집니다.

 

2. MSA 의 기본 구성 요소

MSA 구조를 적용할 때, 많은 요소들이 필요하지만, 개인적으로 반드시 필요하다고 생각되는 3가지 요소가 있습니다.

각 요소별로 역할을 간단히 알아보도록 하겠습니다.

 

1. 디스커버리 서비스 - Discovery Service (a.k.a Eureka Server)

디스커버리 서비스(이하. 유레카 서버)는 하나의 MSA 를 구성하는 서비스들을 관리하는 서비스입니다.

유레카 서버에는 하나의 MSA 구조에서 사용되는 서비스들(ex. 마이크로 서비스, API Gateway 등)의 목록을 관리하게 되고,

유레카 서버에 등록되어 관리되는 서비스들유레카 클라이언트 라고 부릅니다.

나중에 마이크로 서비스를 개발할 때 사용할 FeignClient 기능은 마이크로 서비스가 유레카 서버에 등록되어 있어야 사용이 가능합니다.

 

2. 마이크로 서비스 - Micro Service

마이크로 서비스는 MSA 의 이름에도 들어갈 정도로, MSA 구조를 대표하는 구성요소 입니다.

전체적인 애플리케이션의 비지니스 로직을 구현하는 서비스들로, 마이크로 서비스를 나누는 기준은 각 프로젝트 혹은 애플리케이션 전체에 따라 다르게 설정될 수 있습니다. 

 

3. API gateway 

흔히 Gateway 라고도 불리는 API Gateway클라이언트의 요청을 어떠한 마이크로 서비스에서 처리할 지, 라우팅 해주는 역할을 기본적으로 담당하게 됩니다.

라우팅(Routing) 이란, 클라이언트로 부터 들어온 요청을 받아, 다른 곳으로 해당 요청을 전달하는 행위 입니다.

예를 들면, 온라인 쇼핑몰에서 클라이언트가 1) 사용자 개인정보 조회 요청2) 사용자 주문내역 조회 요청 을 보냈다고 가정해봅시다.

1) 사용자 개인정보 조회사용자가 회원가입할 당시 사용한 아이디, 연락처, 주소 등의 사용자 개인에 대한 정보를 요청한 것이고,

2) 사용자 주문내역 조회사용자가 온라인 쇼핑몰에서 주문했던 내역에 대한 정보를 요청한 것이라면,

개인정보 조회는 사용자 정보를 관리하는 마이크로 서비스에서, 주문내역 조회는 주문 정보를 관리하는 마이크로 서비스에서 각 요청을 처리해야 할 텐데, 이렇게 각 요청을 적재적소에 맞는 마이크로 서비스로 다시 요청을 보내는 역할을 API Gateway 가 담당합니다.

 

 

3. 유레카 서버 & 유레카 클라이언트 설정해보기

그럼 앞에서 알아본 MSA 구성 요소 중 유레카 서버 를 생성해보고, 기존에 개발된 프로젝트를 유레카 클라이언트로 등록해보겠습니다.

 

1. 유레카 서버

1. start.spring.io 에서 dependency 에 Eureka Server 를 선택하고, generate 버튼을 클릭.

2. main 클래스@EnableEurekaServer 어노테이션 추가

이 어노테이션이 추가되면, 이 서비스는 유레카 서버로 사용된다는 것을 의미.

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

// 해당 프로젝트는 유레카 서버 의 역할을 담당하게됨.
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(EurekaServerApplication.class, args);
	}
}

 

3. application.yml(기존엔 application.properties) 파일에 아래와 같은 application 의 기본 설정을 추가

# 유레카 서버를 구동 시, 8761 포트를 사용
server:
  port: 8761

# 해당 서비스의 이름을 shoppingmall-eureka-server 라고 칭함
spring:
  application:
    name: shoppingmall-eureka-server

 

4. 프로젝트를 실행하고, http://localhost:8761 로 접속하면, 아래와 같이 유레카 서버 화면이 나타남

 

여기까지 했다면, 기본적으로 유레카 서버로써 기능을 수행할 수 있습니다.

하지만, 프로젝트를 run 하게 되면 아래와 같은 예외를 볼 수 있습니다.

INFO 19335 --- [           main] c.n.d.s.t.d.RedirectingEurekaHttpClient  : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8761/eureka/}, exception=java.net.ConnectException: Connection refused stacktrace=jakarta.ws.rs.ProcessingException: java.net.ConnectException: Connection refused
	at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:275)
	at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:300)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:662)
	at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:697)
	at org.glassfish.jersey.client.JerseyInvocation.lambda$runInScope$3(JerseyInvocation.java:691)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:390)
	at org.glassfish.jersey.client.JerseyInvocation.runInScope(JerseyInvocation.java:691)
	at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:661)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:413)
	at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:313)
... 이하 생략

앞으로 생성할 유레카 클라이언트들은 서비스 중인 유레카 서버에 Http 요청을 보내 유레카 서버에 등록되게 됩니다. 

그리고 유레카 서버 자신 또한 유레카 서버에 Http요청을 보냄으로써 유레카 서버 자신 또한 유레카 클라이언트로 등록하게 됩니다.

하지만, 이 과정에서 아직 실행 중인 유레카 서버가 없어서, Http 요청이 보내지지 않아서 발생하는 예외 입니다. (Connection refused)

 

즉, 유레카 서버 자신을 굳이 유레카 클라이언트로 등록할 필요가 없기 때문에, 유레카 서버는 유레카 클라이언트로 등록하지 않겠다는 설정을 아래와 같이 추가로 해주어야 합니다.

server:
  port: 8761

spring:
  application:
    name: shoppingmall-eureka-server

# 이 부분이 추가되면, 유레카 서버에 해당 서비스를 유레카 클라이언트로 등록하지 않겠다는 의미
eureka:
  client:
    registry-with-eureka: false
    fetch-registry: false

설정을 변경하고 다시 유레카 서버를 실행해보면, 예외는 발생하지 않고, http://localhost:8761 에 접속해도 등록된 애플리케이션이 없는 것을 확인할 수 있습니다.

유레카 서버에 등록된 애플리케이션이 없음이 확인됨.

 

2. 유레카 클라이언트 - 마이크로 서비스

그럼, 실제 모놀로식으로 개발된 저의 토이 프로젝트를 마이크로 서비스를 적용해서 유레카 서버에 등록해보겠습니다.

토이 프로젝트 환경은 아래 버전이니 참고바랍니다.
SpringBoot 2.7.4 (Spring 5.3)
Java 11
Spring Cloud Starter Netflix Eureka Client 3.1.4

 

먼저, 유레카 서버에 서비스 등록을 위해 유레카 클라이언트 의존성과 관련 설정을 아래와 같이 추가합니다.

ext {
	set('springCloudVersion', "2021.0.5")
}

dependencies {
	// 중략 //

	// spring eureka client
	implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
}

dependencyManagement {
	imports {
		mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
	}
}

 

build.gradle 빌드가 완료되면, application.yml 파일에 유레카 클라이언트 관련 설정을 추가합니다.

# eureka server 에 등록될 service 명칭
spring:
  application:
    name: main-service

# eureka client 설정
# eureka client 가 고유의 instance-id 를 갖게 하기 위해, 서비스의 port를 random.value 로 지정
# eureka server 에 서비스 등록을 위해 register-with-eureka, fetch-registry 를 true 로 설정
# service-url.defaultZone 은 eureka server 의 도메인 정보 추가
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

 

마지막으로, main 클래스에 해당 프로젝트를 실행할 때, Eureka Client 로 처리하겠다는 annotation을 추가합니다.

// @EnableDiscoveryClient 추가
// Discovery Service(Eureka Server) 의 Client 로 등록하기 위해 추가
@EnableDiscoveryClient
@SpringBootApplication
public class ShoppingMallApplication {
	public static void main(String[] args) {
		SpringApplication.run(ShoppingMallApplication.class, args);
	}
}

 

이제 프로젝트를 실행하고, http://localhost:8761 에 접속해보면, 아래와 같이 application 에 MAIN-SERVICE 가 등록됨을 확인할 수 있습니다.

이렇게 되면, 현재 유레카 서버의 MAIN-SERVICE 라는 이름의 유레카 클라이언트 1개가 등록되어 있음을 나타냅니다.

 


 

출처 : 인프런 강의 - SpringCloud로 개발하는 마이크로서비스 애플리케이션(MSA), Dowon Lee

강의링크 : 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 Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) - 인프런 | 강의

Spring framework의 Spring Cloud 제품군을 이용하여 마이크로서비스 애플리케이션을 개발해 보는 과정입니다. Cloud Native Application으로써의 Spring Cloud를 어떻게 사용하는지, 구성을 어떻게 하는지에 대해

www.inflearn.com

 

댓글