1. Spring Cloud란?
Spring Cloude는 스프링에서 마이크로서비스 개발을 위해 다양한 도구와 서비스를 제공하는 프레임 워크의 확장 기능이다. 즉, MSA 를 쉽게 구현하고 운영할 수 있도록 도움을 주는 프레임 워크이다.
Spring Cloud는 API 게이트웨이, 서비스 디스커버리, 로드밸런싱, 서킷 브레이커, 구성 관리 등 다양한 기능을 제공한다.
2. 기능 소개
주요 기능 | 기능 설명 | 구현체 |
서비스 디스커버리 | 모든 서비스의 위치를 저장하고 인스턴스의 상태를 주기적으로 확인 | Eureka , Consul, Zookeeper |
로드 밸런싱 | 서비스 인스턴스 간의 부하를 분산시켜주는 역할 서비스 디스커버리로 부터 서비스 인스턴스 리스트를 제공받아 로드밸런싱에 사용 요청 실패시 다른 인스턴스로 전환됨. |
Ribbon, Spring Cloud LoadBalancer |
API 게이트웨이 | 모든 요청을 중앙에서 관리하는 역할, 요청에 따라 적절한 서비스로 요청전달 보안(인증/인가 처리), 로깅 을 관리 할 수 있음. Filter 로 구성되어 있 |
Zuul, Spring Cloud Gateway |
구성 관리 | 설정 파일을 중앙에서 관리해 주는 역할 설정 변경시 서비스 재시작 없이 실시간 반 |
Spring Cloud Config |
서킷 브레이커 | 호출 실패를 감지하고 호출 실패시 대체 로직을 실행하여 시스템 안정성 유 | Hystrix, Resilience4j |
강의를 기반으로 이해를 확실하게 하기 위해 Spring cloud 아키텍쳐를 그려봤다.
유저가 서버로 요청을 하게 되면 api gateway 에 의해서 인증/인가 처리를 완료하고, 요청에 맞는 각각의 인스턴스(앱) 에 요청을 보내게 된다. 각 인스턴스들은 erueka에 등록되어 있고, 비즈니스 로직을 처리하기 위해 eureka로 부터 인스턴스의 위치를 조회하고 인스턴스끼리 요청을 주고 받는다. 비지니스 로직 처리중에 error 가 발생하면 서킷 브래이커가 에러를 감지하고 에러를 대처할 다른 로직을 수행하던가 alert 처리를 하게 된다.
로드 밸런싱은 한 어플리케이션에 트래픽이 몰린다면, 여러개의 인스턴스로 구성을 할 수 있는데, 같은 서비스를 제공하는 인스턴스가 있을때, 각각 설정한 알고리즘에 의해서 트래픽을 고르게 분산시키는 역할이다.
3.1 Eureka 서버 생성
erueka server , food , order 어플리케이션을 만들어서 erureka에 등록해 보는 과정을 진행하겠다.
ServerApplication.java
@SpringBootApplication
@EnableEurekaServer
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
EurekaServer 로 사용할 어플리케이션에 @EnableEurekaServer 어노테이션을 선언하여, Eureka server 를 생성한다.
application.properties
spring.application.name=server
server.port=1080
// 유레카 서버에 자신을 등록하지 않도록 false
eureka.client.register-with-eureka=false
//클라이언트 서버로부터 레지스트리를 가져올지에 대한 여부
eureka.client.fetch-registry=false
// 유레카 서버의 호스트 이름 설정
eureka.instance.hostname=localhost
// 유레카가 클라이언트와 서버 통신하기 위한 기본 서비스 url
eureka.client.service-url.defaultZone=http://localhost:1080/eureka/
eurka 서버로 등록하기 위한 application.properties 설정이다.
3.2 Eureka Client 서버 등록
인스턴스 어플리케이션을 만들면 eurka에 등록을 해줘야 한다.
Food > Food application.properties
spring.application.name=food
server.port=1081
eureka.client.service-url.defaultZone=http://localhost:1080/eureka/
Oreder > Order application.properties
spring.application.name=food
server.port=1081
eureka.client.service-url.defaultZone=http://localhost:1080/eureka/
유레카 서버와 클라이언트 설정을 완료했다면, 유레카 서버 -> Food -> Order 순으로 서버를 실행한다.
http://localhsot:1080/ 에 접속하게 되면 두개의 인스턴스가 등록된걸 볼 수 있다.
4. 로드밸런싱 FeignClient 와 Ribbon
FeignClient는 Spring Cloud 에서 제공하는 HTTP 클라이언트로, 어노테이션을 통 Restful api 웹 서비스를 호출할 수 있다.
Eureka와 통합해서 서비스 인스턴스 목록을 동적으로 조회하고 로드 밸런싱을 수행 할 수 있다. FeignClien는 Ribbon이 x통합되어 있어 자동으로 로드밸런싱을 수행한다,.
Application 에 @EnableFeignClients를 선언하여 Feigncilent 를 설정한다.
@SpringBootApplication
@EnableFeignClients
public class FoodApplication {
public static void main(String[] args) {
SpringApplication.run(FoodApplication.class, args);
}
}
@FeignClient(name = "order-service")
public interface MyServiceClient {
@GetMapping("/order")
String getResponse(@RequestParam(name = "param") String param);
}
FoodApplication에서 order 서비스의 api 를 요청하고 싶다면 FeignClient 인터페이스 @FeignClient(name =" 서비스 등록명") 을 선언해서 가져오면된다.
@FeignClient(name =" 서비스 등록명") Erueka에 등록된 서비스 이름을 참조하여 인스턴스 목록을 가져오고 Ribbon에 의해서 로드 밸런싱을 구행하게 된다.
5. Spring Gateway
Spring GateWay는 클라이언트 요청을 적절한 서비스로 라우팅하고 필터링 기능을 제공한다.
필터링을 통해 인증/인가, 로깅 처리를 할 수 있다.
application.yml 에서 라우팅 설
spring:
cloud:
gateway:
discovery:
locator:
enabled: true # 서비스 디스커버리를 통해 동적으로 라우트를 생성
routes:
- id: orders-service # 라우트 식별자
uri: lb://orders-service
predicates:
- Path=/orders/** # /users/** 경로로 들어오는 요청을 이 라우트로 처리
- id: foods-service # 라우트 식별자
uri: lb://foods-service #
predicates:
- Path=/foods/** #/orders/** 경로로 들어오는 요청을 이 라우트로 처리
eureka:
client:
service-url:
defaultZone: http://localhost:1080/eureka/
필터를 구현하기 위해선 GlobalFilter, GatewayFilter 인터페이스를 implement 해서 filter 메소드를 오버라이드 해야한다.
serverWebExchange 는 http 요청과 응답을 캡슐화 한 객체로 exchange.getRequest()로 요청을 가져오고, exchange.getRespose()로 응답을 가져온다.
//Pre 요청이 처리되기 전
@Component
public class PreFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 요청 로깅
System.out.println("Request: " + exchange.getRequest().getPath());
return chain.filter(exchange);
}
@Override
public int getOrder() { // 필터의 순서를 지정합니다.
return -1; // 필터 순서를 가장 높은 우선 순위로 설정합니다.
}
}
// Post 필터 요청이 처리된 후, 응답 반환 전
@Component
public class PostFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
// 응답 로깅
System.out.println("Response Status: " + exchange.getResponse().getStatusCode());
}));
}
@Override
public int getOrder() {
return -1;
}
}
Post 필터를 보면 then 메소드 내에서 응답로깅을 처리하는데, 비동기통신을 완료하고 나서 filter처리를 해야하기 때문이다. 구현 구조를 기억해 두었다가, 필요할때 해당 코드를 참고해서 필요한 부분만 수정해서 사용하는걸 추천하셨다.
마무리
프로젝트할때 모놀리식 아키텍처만 개발해봐서 MSA 개발 방식이 궁금했다. 이번 강의를 통해 MSA 의 전체적 흐름과 용어에 많이 익숙해 진것같다. 그리고 상당히 복잡하고.... 각각 설정하는 파일들이 어렵게 느껴졌다.
그래도 이번에 MSA 흐름에 확실하게 이해했기 때문에 다음에 구현할때 좀 더 쉽게 구현할 수 있을것 같다.😁
'Programing > Spring' 카테고리의 다른 글
Redis 개념과 사용법 알아보기 (0) | 2025.03.05 |
---|---|
Spring JPA 관계 이해하기 (0) | 2025.02.07 |
Spring Bean 수동 등록하기 + 같은 타입의 Bean이 여러개 라면? (1) | 2025.02.05 |
Spring JPA Auditing 적용해 보기 (1) | 2025.02.04 |