gony-dev 님의 블로그

2. Spring Cloud MSA 본문

Goorm x Kakao Project/1회차 프로젝트

2. Spring Cloud MSA

minarinamu 2024. 12. 18. 00:05

카카오 x 구름 부트캠프의 회고록 2회차이다!
지난 시간에는 간단한 프로젝트의 소개와 MSA를 사용하는 이유에 대해 알아보았다.
MSA는 서비스의 수평적 확장과 독립성을 위해 사용하는 아키텍쳐로
팀 간의 협력을 용이하게 하고, 유지보수에 특화되어 있다는 특징이 있었다.

이번 시간에는 Spring에서 MSA를 사용하기 위해 필요한 요소들을 알아보도록 하자!

1. Spring Cloud MSA Component

  1. Spring Cloud Gateway
    • URL 주소에 대해 여러 세부 경로에 따라 각각의 스프링부트 어플리케이션에
      분배하는 역할을 수행한다.
  2. Spring Cloud Eureka Server
    • 모니터링 서버로 Eureka Client 설정을 해둔 서버를 Eureka Server에 명시한다.
    • 모니터링 기능과 함께 Spring Cloud Gateway에 목록을 전달하여 Gateway가 로드밸런싱 대상을 설정하도록 한다.
  3. Spring Cloud Eureka Client
    • Eureka Server에 등록되는 요소로 스프링 부트 어플리케이션과 같은 여러 스프링 프레임워크 서버에 설정이 가능하다.
  4. Spring Config Server
    • 환경 변수를 제공하는 서버로 특정 경로에 접근하면 사전에 설정해둔 변수들을 제공 받을 수 있다.
    • MSA를 구축하면 각각의 스프링 부트 어플리케이션에 "application.yml"에 값을 명시하는 것이 아닌 config server로부터 데이터를 받아서 사용한다.
  5. Config Repository
    • Config Server는 단순하게 데이터를 전달하는 역할을 하지만
      데이터는 Config Server Repository라는 저장소를 빌려 저장한다.
  6. Spring Config Client
    • Config Server로부터 환경 변수 데이터를 받기 위한 Client 서버를 설정한다.

2. Spring Config

우선 MSA에서 중요한 부분 중 하나인 환경 변수를 설정하고 제공하는 Config에 대해 알아보도록 하자!

1. Config 저장소 종류

  • Config Server는 데이터를 전달하는 매개체 역할만 수행하고, 실제 정보를 담을 영속성의 경우 DB, Git Service 등을 사용한다.
  • Config 영속성 종류:
    • Git Service(Most used!)
    • RDB
    • NoSQL
    • Redis
    • File..
    • LocalPath
  • 현 프로젝트는 navtive 프로파일을 사용하여 로컬 경로를 통해 설정 관리를 하고 있다.
    이는 운영 환경에서 발생할 수 있는 문제와 유지보수성으로 인해 비추천하기에 후에 Git 저장소에 설정하는 방식으로 변경할 예정이다.

2. Config 서버

  • 환경 변수를 제공하는 서버로 특정 경로에 접근하면 사전에 설정해둔 변수들을 제공 받을 수 있다.
  • 해당 모듈의 Application.class에는 다음과 같은 어노테이션을 명시한다.
@EnableConfigServer

이어서 application.yml에는 Config 저장소를 연결하기 위해 다음과 같이 설정한다.(Git Repository에 넣은 경우)

server.port=8888

spring.cloud.config.server.git.uri=주소
spring.cloud.config.server.git.ignoreLocalSshSetting=true
spring.cloud.config.server.git.private-keys=비밀키내용

3. Config 클라이언트

  • 단순히 서비스 로직을 수행하는 스프링 어플리케이션이다.
  • 어플리케이션이 Config Client 설정을 통해 Config Server에서 보내주는 데이터를 받을 수 있다.

Server와의 연동을 위해서는 의존성과 설정을 해주어야 한다.

build.gradle

  • Config Client에 대한 의존성을 추가하였다.
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.6'
    id 'io.spring.dependency-management' version '1.1.3'
    id 'jacoco'
}

group = 'server'
version = '1.0-SNAPSHOT'


repositories {
    mavenCentral()
}

dependencies {

    implementation 'org.springframework.cloud:spring-cloud-starter-config'
}

ext {
    set('springCloudVersion', '2023.0.4')
}

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

application.yml

  • Git Repository에 ms1-dev.properties 파일을 올려놓았다면 yml 구성은 다음과 같아진다.
spring.application.name=ms1
spring.profiles.active=dev
spring.config.import=optional:configserver:http://아이디:비밀번호@아이피:포트

 


3. Eureka Server 구축

Eureka 서버란?

  • Eureka 서버는 MSA 환경에서의 마이크로서비스들을 모니터링하는 역할을 한다!
  • 또한 Gateway에게 마이크로서비스에 대한 상세정보들을 제공하여 유동적으로 통신하게끔 하며,
    요청을 분산할 수 있도록 로드 밸런싱을 지원한다!

1. Eureka Server

Eureka 서버를 구현하기 위해서는 Eureka Server와 Spring Security를 반드시 추가해 주어야 한다.
Security는 요청되는 uri에 대한 접근을 설정하고 보안성을 유지하기 위함이다!

 

build.gradle

 plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.6'
    id 'io.spring.dependency-management' version '1.1.3'
    id 'jacoco'
}

group = 'server'
version = '1.0-SNAPSHOT'


repositories {
    mavenCentral()
}

dependencies {
	
    implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-server")
}

ext {
    set('springCloudVersion', '2023.0.4')
}

dependencyManagement {
        imports {
            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
        }
    }
}
  • 위와 같이 eureka-client에 대한 의존성을 추가하면
    Appication.class에 다음 어노테이션을 추가하면 된다.
@EnableConfigServer
  • 마지막으로 application.yml에 설정을 하면 Eureka 서버를 사용할 수가 있다!

application.yml

server.port=8761

// 아래의 2개 코드는 Eureka 서버가 자기 자신을 등록하지 않게 하기 위해 설정한다!
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

2. Eureka Client

  • Eureka Client란 Eureka 서버에서 모니터링 및 관리를 원하는 요소들을 설정을 통해 등록할 수 있게 한다.
  • 클라이언트를 설정하는 방법에는 build.gradle에 의존성을 추가하고 어노테이션을 등록하여 사용하는 방법이 있다!

build.gradle

 

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.3.6'
    id 'io.spring.dependency-management' version '1.1.3'
    id 'jacoco'
}

group = 'server'
version = '1.0-SNAPSHOT'


repositories {
    mavenCentral()
}

dependencies {
	
    implementation("org.springframework.cloud:spring-cloud-starter-netflix-eureka-client")
}

ext {
    set('springCloudVersion', '2023.0.4')
}

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

 

  • 그리고 application.class에 다음 어노테이션을 추가하자.
@EnableDiscoveryClient

 

application.yml

server.port=8080

// 아래의 2개 코드는 Eureka 서버가 자기 자신을 등록하지 않게 하기 위해 설정한다!
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.service-url.defaultZone=http://아이디:비밀번호@아이피/포트/eureka

4. Spring Cloud Gateway

스프링 부트 Gateway란?
MSA 환경에서 클라이언트들로부터 오는 요청을 받아 경로와 조건에 맞는 마이크로서비스 로직에 요청을 전달한다.
무중지 상태로 모든 요청을 전달하기에 설정을 확실히 해주어야 한다!

 

특징은?

  • 게이트웨이는 비즈니스 로직처리보다는 단순하게 지나가는 통로 역할을 맡기에 Non-blocking 방식으로 동작하는 WebFlux와 Netty Engine을 사용한다.
  • WebFlux는 기존에 사용했던 JPA 같은 블로킹 방식의 의존성들을 모두 사용하지 못하기에 많은 학습이 요구된다.

 

1. Gateway Routing

application.yml을 통한 경로를 설정해보자!

server:
	port: 8080

spring:
	cloud:
        gateway:
        	routes:
            	- id: ms1
                  uri: http://localhost:8081
                  predicates:
                  	- Path=/ms1/**
                - id: ms1
                  uri: http://localhost:8082
                  predicates:
                  	- Path=/ms2/**

 

만일 application.yml을 이용한 방법이 마음에 들지 않는다면, Config 클래스를 통해 작성할 수도 있다!

@Configuration
public class RouteConfig {
	
    @Bean
    public RouteLocator ms1Route(RouteLocatorBuilder builder){
    	return builder.routes()
        	.route("ms1", r -> r.path("/ms1/**")
            	.uri("http://locahlhost:8081"))
            .route("ms1", r -> r.path("/ms2/**")
            	.uri("http://locahlhost:8082"))
            .build();
    }
}

5. Gateway Filter

1. Global Filter

  • Spring Cloud Gateway에서 Global Filter는 모든 라우팅에 대해 적용되는 필터이다.
  • 클라이언트의 요청은 다음과 같이 이동되며 같은 필터라도 마이크로서비스를 접근하기 이전이라면 pre, 이후면 post라고 명명한다.
    1. 필터
    2. 마이크로서비스
    3. 필터
@Component
@Slf4j
public class GlobalFilter implements GlobalFilter, Ordered {

	@Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
    	
        log.info("pre global filter order -1");
        
        retur chain.filter(exchange)
        	.then(Mono.fromRunnable(() -> {
            	log.info("post global filter order -1");
                
            }));
    }
    
    @Override
    public int getOrder() {
    	return -1;
    }   
}
  • 위의 코드를 통해 service의 필터를 pre와 post를 통해 거치는 과정을 볼 수 있다.

2. Local Filter

  • Spring Cloud Gateway에서 지역 필터는 특정 마이크로서비스 라우팅에 대해서만 동작을 진행하는 필터이다.
@Component
public class LocalFilter extends AbstractGatewayFilterFactory<LocalFilter.Config> {
	
    public LocalFilter() {
    
    	super(Config.class)
    }
    
    @Override
    public GatewayFilter apply(Config config) {
    	
        return (exchange, chain) -> {
        
        	if(config.isPre()) {
            	log.info("pre local filter 1");
            }
            
            return chain.filter(exchange)
            	.then(Mono.fromRunnable(() -> {
                	if(config.isPost()) {
                    	log.info("post local filter 1");
                    }
                }));
        };
    }
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class Config {
    	private boolean pre;
        private boolean post;
    }
}

'Goorm x Kakao Project > 1회차 프로젝트' 카테고리의 다른 글

3. Maven에서 Gradle  (0) 2024.12.18
1. MSA를 사용하는 이유  (1) 2024.12.13