MSA Phase 1. Springboot(1)

devty·2023년 7월 22일
3

MSA

목록 보기
1/14
post-thumbnail

서론

MSA 환경에서 Springboot를 관리하는 방법

  • MSA 환경에서 Springboot를 지원하는 여러 툴들이 있습니다.
    1. Spring Cloud
      • 마이크로 서비스를 쉽게 개발하고 관리할 수 있도록 도와준다.
      • 로드 밸런싱, 서킷 브레이커 등을 지원한다.
    2. Spring Cloud Gateway
      • API Gateway 역할을 수행한다.
      • 요청을 적절한 마이크로 서비스로 라우팅하고 필터링하는 등의 기능을 제공한다.
    3. Spring Cloud Netflix Eureka
      • 클라우드 환경에서 동작하는 수많은 마이크로 서비스 인스턴스들을 효율적으로 관리해준다.
      • Eureka 클라이언트는 Eureka 서버에 자신의 위치 정보를 보고한다.
      • 서비스 등록, 서비스 발견, 로드밸런싱 등을 지원한다.
    4. Spring Cloud Config
      • 분산 시스템에서 중앙 집중식 설정을 제공한다. 이를 통해 모든 마이크로 서비스 인스턴스의 환경 설정을 한 곳에서 관리할 수 있다.

본론

Springboot 프로젝트 관리

  • 거두절미 하고 MSA 환경을 만들기 위한 준비를 해야한다.
  • MSA 환경으로 만들기 위해서는 프로젝트 구조도 생각을 해야한다.
  • 하나의 Root 디렉토리에서 각 마이크로 서비스를 전체 빌드할 것인지, 마이크로 서비스 단위로 각각 빌드를 하게 두어야할지 먼저 고민을 해봐야한다.
  • 나는 MSA에서는 느슨한 결합(제일 많이 들었던 용어)과 빌드 시간에 대한 리소스를 생각해봤을 때 각각 나눠서 빌드를 해주는게 좋을 것이라고 생각을 하였다.
  • 따라서 앞으로 얘기하는 부분은 각 마이크로 서비스에 각각의 빌드 및 배포를 얘기할 예정이다.

Spring Cloud Gateway

  • Spring Cloud Gateway는 각 마이크로 서비스에 대한 호출을 정의해준다.
  • 따라서 Spring Cloud Gateway는 Proxy Server와 같은 개념이라고 생각하면 된다.
  • 주요 기능은 다음과 같습니다.
    1. 경로 기반 라우팅
    2. 필터
    3. 서킷 브레이커 통합
  • 장점
    1. 비동기/논블로킹 구조
      • Netty/Reactor를 기반으로 구축되어 비동기 및 논블로킹 I/O를 지원합니다. 이로 인해 고성능과 확장성이 향상됩니다.
    2. 편리한 통합
    3. 다양한 기능 지원
      • 인증, SSL, 로드 밸런싱 등의 다양한 기능을 지원합니다.
  • 단점
    1. 학습 곡선
      • 다양한 기능을 모두 활용하려면 시간과 노력이 필요합니다.
    2. 설정 복잡성

Spring Cloud Netflix Eureka

  • 서비스 디스커버리를 위한 솔루션입니다. 서비스 디스커버리는 마이크로서비스 환경에서 서비스간의 통신을 관리하고, 서비스 인스턴스의 위치를 추적하는 데 사용됩니다.
  • 주요 기능은 다음과 같습니다.
    1. 서비스 등록
      • 서비스 인스턴스가 시작할 때 Eureka 서버에 등록하고, Eureka 서버는 모든 등록된 서비스 인스턴스에 대한 정보를 유지합니다.
    2. 서비스 발견
      • 서비스 인스턴스가 다른 서비스를 찾아야 할 때 Eureka 서버에 요청하여 필요한 서비스의 인스턴스 정보를 얻습니다.
    3. 서비스 간 접근 가능성 확인
      • Eureka는 서비스 인스턴스의 가용성을 확인하기 위해 주기적으로 하트비트를 보냅니다.
  • 장점
    1. 스프링 통합
      • Eureka는 스프링과 잘 통합되어 있어, 스프링 기반의 마이크로서비스 환경에서 쉽게 사용할 수 있습니다.
  • 단점
    1. 폐쇄된 환경 지원
      • 기본적으로 AWS 환경에 최적화되어 있습니다.
      • 따라서 AWS 환경이 아니면 환경 구성이 어려울 수 있다.

Eureka, Gateway는 왜 동시에 존재하는가?

  • Eureka → Discovery Registry로 이름 그대로 외부의 서비스(User, Mate)들이 마이크로 서비스를 검색(Discovery)과 등록(Registry)을 위한 서비스 입니다.
  • API Gateway → 모든 클라이언트의 요청을 받아 설정해 놓은 라우팅 설정에 따라서 각각의 endPoint로 클라이언트 대신에 요청을 보내고 응답을 받아 클라이언트에게 전달하는 프록시 역할을 합니다.
  • Eureka 서비스가 User, Mate 서비스를 모듈화 해둔 뒤 Eureka -> API Gateway로 등록/해제 된 서비스들의 정보를 전달해 주면, API Gateway가 해당 정보를 기억하고 있다가, 자신이 사용해야 하는 시점에 해당 서비스로 요청을 전달하게 됩니다.

MSA 프로젝트 구조

  • 위에서 설명 했듯이 Root 디렉토리가 있고 그 안에서 새로운 모듈을 생성하여 새로운 서비스를 만들어준다.

Spring Cloud Gateway 코드

  • build.gradle
    plugins {
        id 'java'
        id 'org.springframework.boot' version '2.7.12'
        id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    }
    
    group = 'apiGateway'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '11'
    
    repositories {
        mavenCentral()
    }
    
    ext {
        set('springCloudVersion', "2021.0.4")
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
    
    		// spring cloud gateway
        implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
    		
    		// spring cloud eureka
    		implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    }
    
    dependencyManagement {
        imports {
    				// spring cloud version
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        }
    }
    
    tasks.named('test') {
        useJUnitPlatform()
    }
    • spring cloud gateway를 사용해주기 위해 dependencies에 추가해준다.
    • spring cloud eureka를 사용해주기 위해 dependencies에 추가해준다.
    • spring cloud를 사용하기 위해 version을 설정해준다.
  • application.yml
    server:
      port: 8000
    
    eureka:
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:8761/eureka
    
    spring:
      application:
        name: ApiGateway-service
      cloud:
        gateway:
          routes:
            - uri: lb://user-service
              predicates:
                - Path=/user-service/**
            - uri: lb://mate-service
              predicates:
                - Path=/mate-service/**
            - uri: lb://product-service
              predicates:
                - Path=/product-service/**
            - uri: lb://stock-service
              predicates:
                - Path=/stock-service/**
            - uri: lb://order-service
              predicates:
                - Path=/order-service/**
    • gateway의 기본 포트인 8000으로 지정해준다.
    • eureka
      • register-with-eureka: true → 이 서비스가 Eureka 서버에 자신을 등록하도록 한다.
      • fetch-registry: true → 이 서비스가 Eureka 서버에 등록된 모든 서비스의 정보를 가져와서 캐싱하도록 한다. 이를 통해 이 서비스는 다른 서비스를 찾을 수 있게 된다.
      • service-url: defaultZone: http://localhost:8761/eureka → Eureka 서버의 URL을 지정한다. 이 서비스는 이 URL을 통해 Eureka 서버에 접속하게 됩니다.
    • cloud.gateway.routes Spring Cloud Gateway에서 사용하는 라우트 설정을 정의합니다. 각 라우트는 uri와 predicates를 가집니다.
    • uri: lb://*-service → 라우트의 대상 URI를 지정합니다. 여기서 lb는 로드 밸런싱을 의미하며 요청이 로드 밸런싱 되어 일정하게 통신을 받게 된다.
    • predicates: - Path=/*-service/** → 라우트가 적용될 조건을 뜻한다.

Spring Cloud Eureka 코드

  • build.gradle
    plugins {
        id 'java'
        id 'org.springframework.boot' version '2.7.12'
        id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    }
    
    group = 'eureka'
    version = '0.0.1-SNAPSHOT'
    sourceCompatibility = '11'
    
    repositories {
        mavenCentral()
    }
    
    ext {
        set('springCloudVersion', "2021.0.4")
    }
    
    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter'
    
    		// spring cloud eureka
    		implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    }
    
    dependencyManagement {
        imports {
    				// spring cloud version
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        }
    }
    
    tasks.named('test') {
        useJUnitPlatform()
    }
    • Gateway service와 같이 Eureka를 사용하기에 빌드에 넣어주며, Cloud도 마찬가지로 사용하기에 버전 설정을 해준다.
  • EurekaServiceApplication.java
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaServiceApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(EurekaServiceApplication.class, args);
    	}
    }
    • 기본적인 스프링부트를 실행하기 위한 SpringBootApplication이다.
    • 단, 다른점이 있다면 해당 서비스는 Eureka로 사용될 것이므로 EnableEurekaServer 어노테이션을 붙여주어 Eureka server로 사용하면 된다.

User-serivce 코드

  • build.gradle
    plugins {
        id 'java'
        id 'org.springframework.boot' version '2.6.1'
        id 'io.spring.dependency-management' version '1.0.15.RELEASE'
    }
    
    group = 'user'
    version = '0.0.1-SNAPSHOT'
    
    java {
        sourceCompatibility = '11'
    }
    
    repositories {
        mavenCentral()
    }
    
    ext {
        set('springCloudVersion', "2021.0.4")
    }
    
    dependencies {
        // common module
        implementation project(path: ':common')
    
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
        implementation 'org.springframework.boot:spring-boot-starter-security'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter-validation'
        implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    
        testImplementation 'junit:junit:4.13.1'
        compileOnly 'org.projectlombok:lombok'
        runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
        testImplementation 'org.springframework.security:spring-security-test'
    
        // Junit5
        testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
    
        // Gson
        implementation 'com.google.code.gson:gson:2.9.0'
    
        // netflix-eureka
        implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client:3.1.0'
    
        // kafka
        implementation 'org.springframework.kafka:spring-kafka'
    }
    
    test {
        useJUnitPlatform()
    }
    • 다 볼 필요는 없다. 우리는 Eureka 서비스에 등록이 필요하므로 Eureka에 관련된 dependencies만 추가해 주었다.
    • 그 부분은 netflix-eureka 주석 된 부분이다.
  • application.yml
    server:
      port: 8081
      servlet:
        context-path: /user-service
    
    spring:
      application:
        name: user-service
      profiles:
        active: dev
    
    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://localhost:8761/eureka
    • servlet.context-path → 서버가 응답할 요청의 기본 경로를 지정한다.
    • application.name → 여기서는 user-service라고 두었는데 이 부분이 Eureka에 등록되는 이름이다. 따라서 Gateway 서비스에서 routes.uri를 어플리케이션 이름으로 두었는데 Gateway가 Eureka에 등록된 어플리케이션 이름을 확인하기에 동일하게 두어야한다.
    • eureka.instance.instance-id → Eureka 서버에 등록될 때 사용할 인스턴스의 ID를 지정합니다. 여기서는 호스트 이름과 인스턴스 ID, 그리고 랜덤 값 중 하나를 사용하여 유니크한 인스턴스 ID를 생성한다.
    • 밑 Client 부분은 Gateway application.yml 설명과 동일하므로 생략하겠다.
  • UserServiceApplication.java
    @SpringBootApplication
    @EnableDiscoveryClient
    public class UserServiceApplication {
    
    	public static void main(String[] args) {
    		SpringApplication.run(UserServiceApplication.class, args);
    	}
    
    }
    • User Service의 메인 클래스이다.
    • 여기서 주목해서 봐야할 점은 EnableDiscoveryClient 어노테이션인데 해당 어노테이션을 사용하게 되면 Eureka Server에 User Service를 등록하고 다른 서비스들과 통신할 수 있는 능력을 갖게된다.

실행

  • 이제 각각의 서비스를 실행하여 Eureka serivce에 추가가 됐는지 확인하면 된다.
  • 이제 Eureka 서버의 기본 포트인 8761로 접속하면 밑과 같은 화면이 뜰 것이다.
    • 위에서는 Eureka 서비스에 Gateway, User, Mate 이 3가지를 추가하여 잘 들어간 것을 확인할 수 있다.
    • 나머지 서비스들도 틀을 이미 만들어 둔 상태에서 작업을 진행하였다.

다음시간에 계속……

profile
지나가는 개발자

2개의 댓글

comment-user-thumbnail
2023년 7월 22일

정리가 잘 된 글이네요. 도움이 됐습니다.

답글 달기
comment-user-thumbnail
2023년 7월 24일

같이 으쌰 으쌰 해요!!

답글 달기