Easy Understanding

스프링부트로 페이 시스템 구축 도전해보기(초보 난이도) (5) - Spring Cloud를 이용한 간단한 MSA 아키텍쳐 구성하기 본문

Spring

스프링부트로 페이 시스템 구축 도전해보기(초보 난이도) (5) - Spring Cloud를 이용한 간단한 MSA 아키텍쳐 구성하기

appleg1226 2020. 10. 28. 14:54

초보 주의

예전 개발 경험이 적을 때 작성한 거라서 지금 저의 시점으로 보니 너무 도움이 안 되는 글이네요...

솔직히 지우고 싶으나 풋풋함을 기억하기 위해서 남겨둡니다. 

(심지어 지금 결제 도메인 개발 중이라 더 부끄러움)

 

MSA, Spring Cloud란?

MSA라는 단어는 많이들 들어보셨을겁니다.

Micro Service Architecture 를 줄여서 MSA라고 합니다.

 

MSA는 기술/기법으로 여겨지기도 하지만, 단어 자체로는 어떠한 개념을 뜻합니다.

 

Micro: 작게 

Service: 서비스를

Architecture: 구성하라

 

저는 위의 느낌으로 MSA를 이해했습니다.

기존에 하나의 서비스에 여러가지를 넣어서 개발하던 시기와 다른 개발 방식이죠.

 

저의 세 가지 프로젝트들(조회/결제/송금)을 만들면서 중간중간 계속 고민했던 것이 있습니다.

'아 이걸 굳이 이렇게 세 개로 쪼개야 하나?'

'어차피 관리할 DB 자체도 얼마 안되고, 메서드도 한 두개가 끝인데 굳이 이걸 나눠야 하나?'

라는 생각이 계속 들었습니다.

왜냐하면 결제와 송금 서비스는 거의 단일 메서드에 단일 api를 사용하기 때문이었죠.

 

그렇지만 이러한 고민은 대부분의 경우 매우 합당한 고민입니다.

원래대로라면 작은 서비스를 굳이 여러 개의 서버로 쪼갤 필요는 없습니다.

 

서비스를 쪼갤수록 관리해야하는 것들이 굉장히 늘어나기 때문이죠.

 

매 프로젝트별로 의존성 관리, 서버 관리, 보안 적용, 서비스 간의 소통 등 신경써야할 것들이 많이 늘어납니다.

그렇기 때문에 MSA와 기존 단일 서비스 구성의 장단점을 고려하여 아키텍쳐를 결정하는 것은 많은 고려 뒤에 이뤄져야 합니다.

 

저는 스프링을 공부할수록 '아 이거 너무 개발자가 날로 먹을 수 있는 거 아닌가' 라는 생각이 자주 듭니다.

 

스프링의 각종 프로젝트들은 어려운 작업들을 날로 먹을 수 있도록 많이 도움을 줍니다.

어떻게 이렇게 간단하게 자동화를 시켜놨는지... 오히려 패스트푸드 같아서 불안한 느낌도 있습니다.

스프링부트만 해도 기존에 스프링 자체적으로 했던 설정들을 하나도 신경을 쓰지 않게 해주니까 편리하죠.

 

Spring Cloud 프로젝트도 마찬가지입니다.

여러 서비스끼리의 연결을 단지 설정파일만으로 해줄 수 있습니다.

 

Spring Cloud의 목적은 여러 서비스들을 하나의 스프링 Cloud 안으로 모으는 겁니다.

 

- 하나의 구름 안에서 여러 서비스들은 서로를 찾을 수 있습니다.

- 여러 서비스들은 각자의 서비스들을 간편하게 찾아서 소통을 할 수 있습니다.

- 밖에서는 하나의 문을 이용해서 구름 속 서비스를 사용할 수 있습니다.

 

이런 것들을 모아놓은 서비스가 Spring Cloud 입니다.

 

많은 서비스가 있지만 Netflix에서 적용하던 MSA 프로젝트들을 그대로 스프링으로 가져온 것들이 대표적입니다.

 

- Eureka: 각 서비스들을 찾도록 해주는 중앙 연결 타워. 모두들 Eureka를 거쳐서 서로를 식별합니다.

- Zuul: 각 서비스들을 사용해주는 중앙문 같은 존재. Gateway라고 불리우는 기능을 수행합니다. 모든 api 호출은 이 zuul을

            통해서 이루어집니다. 

- Hystrix: 내/외부적으로 각 서비스를 사용하는 데에 문제가 있다면 그것들을 기록하고 방지해주는 역할을 해주는 Circuit

                Breaker 입니다.

- Ribbon: 로드밸런서. 여러 개의 서비스 인스턴스가 있다면 이것을 소프트웨어적으로 분배해주는 역할을 합니다.

 

이외에도 스프링 클라우드에는 여러 서비스 간의 상호작용을 위한 프레임워크들이 있으며, 계속 개발 중에 있습니다.

 

저는 이 중에서 간단하게 Eureka와 Zuul만 적용을 하도록 하겠습니다.


MSA 시스템 구성

제가 구성을 할 아키텍쳐는 다음 그림과 같습니다.

Spring cloud

모든 서비스들은 Eureka 안에서 하나의 이름을 가집니다.

그리고 그 서비스들은 Zuul을 이용해서 외부에서 접근이 가능하게 됩니다.

그리고 각 서비스들은 서로의 이름을 통해서 내부적으로 api, messaging를 이용해서 소통할 수 있게 됩니다.

그래서 저는 위의 그림처럼 Eureka 서버 하나, Zuul 서버 하나를 프로젝트에 추가하도록 하겠습니다.


Eureka 적용

다음은 eureka와 관련된 설정만 남겨놓은 pom.xml 파일입니다.

<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </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>

 

그리고 여기에서 메인 메서드에 다음과 같이 어노테이션을 추가시켜줍니다.

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

}

 

그리고 application.yaml 파일에는 다음과 같이 추가해주면 됩니다.

server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  client:
    fetchRegistry: false   # 이 속성은 다른 유레카 서버의 정보를 가져온다.
    registerWithEureka: false  # 위와 동일
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    enableSelfPreservation: false  # 개발환경에서만 false

 

이렇게 설정해주고 스프링 프로젝트를 켜면 이제 8761 포트를 통해서 Eureka UI dashboard를 이용할 수 있습니다.

 

localhost:8761 화면

아직까지는 다른 프로젝트가 등록되지 않은 상태입니다.

 

이제 user-service의 application.yaml에 다음을 추가하겠습니다.

server:
  port: 8081

spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

이렇게만 추가한 다음 Eureka 대시보드를 확인하면 

 

다음과 같이 제가 등록한 서비스가 유레카를 통해서 발견된 것을 확인할 수 있습니다.

 

다른 서비스들도 위와 같이 설정을 해주고 서버를 띄워주면 

 

 

이렇게 각 서비스들은 각자의 Application name을 가지고 cloud 내에서 소통할 수 있는 기반이 갖춰지게 됩니다.


Zuul 적용

위에서 유레카 프로젝트를 시작할 때 pom 파일을 알려드렸는데, 원래는 spring Initializr를 이용해서 시작했었고,

이게 가장 편합니다.

 

다음과 같이 Zuul 하나만 추가시켜주면 됩니다.

Zuul 프로젝트에서 추가해줘야 할 건 아래 코드를 보시면 Zuul Proxy에 대한 어노테이션과

기본 설정밖에 없습니다.

 

@SpringBootApplication
@EnableZuulProxy
public class ZuulGatewayApplication {

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

}
server:
  port: 8080

zuul:
  routes:
    user:
      path: /user/** 
      serviceId: user-service
    payment:
      path: /payment/**
      serviceId: payment-service
    transfer:
      path: /transfer/**
      serviceId: transfer-service

 

applicaition.yaml 에서는 zuul에서 각 서비스로 어떻게 route할지에 대한 규칙을 설정할 수 있습니다.

저는 user로 시작하는 api 요청은 user-service로, payment로 시작하는 api 요청은 payment-service로 라우팅되도록

설정을 해놨습니다.

 

이제 모든 요청은 localhost:8080을 통해서 진행해야 합니다.

 

예를 들어서 GET localhost:8080/user/{id} 를 요청하면

우리가 user-service로 등록한 8081 포트에 있는 서비스가

자동으로 localhost:8081/{id} 로 라우팅되어 요청에 대한 응답을 받게 됩니다.

 

GET http://localhost:8080/user/{id}  => GET http://localhost:8081/{id}

POST http://localhost:8080/payment/process  => POST http://localhost:8082/process

POST http://localhost:8080/transfer/process  => POST http://localhost:8083/process

 


정리

물론 MSA 서비스를 구성하는 것 자체로는 어떠한 목적을 이뤘다고 보기는 힘듭니다.

이것들을 구성하는 것은 다른 복잡한 작업을 위한 기초 단계일 뿐입니다.

 

하지만 이후로 복잡한 작업들(서비스 간 호출, 보안, 테스팅, 배포) 등을 위한 기초 구성으로서

빨리 끝난다는 것 자체로 생산성에 큰 도움이 될 것이라고 생각합니다.

 

자세한 정보는 spring.io/projects/spring-cloud

을 통해서 찾아보시면 됩니다.

 

 

참고) 마스터링 스프링 클라우드(피요트르 민코프스키)