![Secion 0~2: Micro Service와 Spring Cloud 소개, Service Discovery, API Gateway](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flx9Hm%2Fbtsg4hMK7vm%2FfV12I6OaEHo8WEwiBIYcMk%2Fimg.png)
Secion 0~2: Micro Service와 Spring Cloud 소개, Service Discovery, API GatewayBook & Lecture/이도원님 MSA2023. 5. 22. 00:37
Table of Contents
section 0. Microservice와 Spring Cloud의 소개
MSA 이걸 도대체 왜 할까?
- DB에 트랜잭션 잠금 등으로 시스템이 전면 마비가 되어버린다...
- 리뷰로 DDOS 공격 받듯이 요청이 왔는데... 주문이 마비 되어 버린다.. ㅠㅠ
- 일반적으로 Scale Out보다는 Scale Up이 더 저렴하다
- MSA... 어떻게든 전면마비, 성능 문제, 확장 문제로부터 자유로워지고자 만들어진 시스템 ...
section 1. Service Discovery
- Service Discovery: 서비스를 찾아서 탐색한다.
- 예) localhost:8001, 8002 등 각각 다른 서비스를 등록
- localhost:8001 -> localhost/order 등
- 예) localhost:8001, 8002 등 각각 다른 서비스를 등록
Discovery Service - Eureka
- Server의 개념이다
- 이곳에서 MS를 등록한다
Discovery Service - Client
- Client의 개념이다
- MS 자체이다
server:
port: 9021
spring:
application:
name: user-service
eureka:
client:
register-with-eureka: false # 유레카 서버에 등록할지 여부
fetch-registry: false # 서버와 주기적으로 통신할 지 여부
service-url:
defaultZone: http://127.0.0.1:8761/eureka # 유레카 서버 url
# 강사님이 localhost 보다는 이 표기 법을 선호
Discovery Client 를 실행하는 다양한 방법
- yaml을 직접 수정한다
- 인텔리제이 Run Configuration Button을 수정한다.
- Artifact (War, Jar) 와 Build 명령어 이용
section 2. API Gateway Service
- 사용자의 요청을 대신 받아서 실제 MicroService에게 요청을 한다!
With so many clients and servers in play, it’s often helpful to include an API gateway in your cloud architecture. A gateway can take care of securing and routing messages, hiding services, throttling load, and many other useful things. Spring Cloud Gateway gives you precise control of your API layer, integrating Spring Cloud service discovery and client-side load-balancing solutions to simplify configuration and maintenance.
사용 중인 클라이언트와 서버가 너무 많기 때문에 클라우드 아키텍처에 API 게이트웨이를 포함하는 것이 종종 도움이 됩니다. 게이트웨이는 메시지 보안 및 라우팅, 서비스 숨기기, 부하 조절 및 기타 많은 유용한 작업을 처리할 수 있습니다. Spring Cloud Gateway는 구성 및 유지 관리를 단순화하기 위해 Spring Cloud 서비스 검색 및 클라이언트 측 로드 밸런싱 솔루션을 통합하여 API 계층을 정밀하게 제어할 수 있도록 합니다.
Netflix Zuul
- Spring 2.4 version 이전에 사용 가능
localhost:8080/서비스명
에 요청 오면http://localhost:서비스_포트번호
으로 전달이 가게 하자!localhost:8080/first-service
->http://localhost:8081
localhost:8080/second-service
->http://localhost:8082
server:
port: 8000
spring:
application:
name: my-zuul-service
zuul:
routes:
first-service:
path: /first-service/**
url: http://localhost:8081
second-service:
path: /second-service/**
url: http://localhost:8082
@Slf4j
@Component
public class ZuulLoggingFilter extends ZuulFilter {
@Override
public Object run() throws ZuulException {
log.info("**************** printing logs: ");
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info("**************** " + request.getRequestURI());
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
}
Spring Cloud Gateway
- Zuul과는 다르게 논블락킹을 지원한다
- Server도 Tomcat이 아닌 Netty 기동
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: # forwarding 시켜버리기
- id: first-service
url: http://localhost:8081/
predicates: # 조건절
- Path=/first-service/**
- id: second-service
url: http://localhost:8082/
predicates: #
- Path=/second-service/**
- 예시)
xxx:8000/first-service/welcome
로 요청이 오면localhost:8081/first-service/welcome
으로 라우팅한다! - 다만,
/MS명
으로 요청이 오면:MS포트번호_/MS명
로 고스란히 요청이 가게 되는 불편함이 있다- 추후에 수정하는 방법을 알려주시는 것 같다
header를 추가하는 방법(spring.cloud.gateway.routes
)은 아래 두 가지가 있다
@Configuration
class FilterConfig {
@Bean
fun gatewayRoutes(builder: RouteLocatorBuilder): RouteLocator =
builder.routes {
route {
path("/first-service/**")
.filters {
it
.addRequestHeader("first-request", "first-request-value")
.addResponseHeader("first-response", "first-response-value")
}
.uri("http://localhost:8081")
}
route {
path("/second-service/**")
.filters {
it
.addRequestHeader("second-request", "second-request-value")
.addResponseHeader("second-response", "second-response-value")
}
.uri("http://localhost:8082")
}
}
}
spring:
...
cloud:
gateway:
routes:
- id: first-service
uri: http://localhost:8081/
predicates:
- Path=/first-service/**
filters:
- AddRequestHeader=first-request, first-request-value
- AddResponseHeader=first-response, first-response-value
- id: second-service
uri: http://localhost:8082/
predicates:
- Path=/second-service/**
filters:
- AddRequestHeader=second-request, second-request-value
- AddResponseHeader=second-response, second-response-value
(Path) /first-service/**
로 요청이 오면 (uri) http://localhost:8081/
로 라우팅한다
커스텀 필터를 등록해보자
커스텀 필터
@Component
class CustomFilter : AbstractGatewayFilterFactory<CustomFilter.Config>() {
private val log = LoggerFactory.getLogger(CustomFilter::class.java)
override fun apply(config: Config?): GatewayFilter =
GatewayFilter { exchange: ServerWebExchange,
chain: GatewayFilterChain ->
val request: ServerHttpRequest = exchange.request
val response: ServerHttpResponse = exchange.response
log.info("custom pre filter: request id: {}", request.id)
chain
.filter(exchange)
.then(Mono.fromRunnable {
log.info("custom post filter: request id: {}", response.statusCode)
})
}
class Config {
// put the configuration properties if exist
}
}
설정
spring:
cloud:
gateway:
routes:
- id: first-service
...
filters:
- CustomFilter
- id: second-service
...
filters:
- CustomFilter
글로벌 필터
도 크게 다른건 없다
@Component
class GlobalFilter : AbstractGatewayFilterFactory<GlobalFilter.Config>(Config::class.java) {
val log = LoggerFactory.getLogger(GlobalFilter::class.java)!!
override fun apply(config: Config?): GatewayFilter =
GatewayFilter { exchange: ServerWebExchange,
chain: GatewayFilterChain ->
if (config == null) {
throw NullPointerException("config should not be null")
}
log.info("Global Filter baseMessage: {}", config.baseMessage)
if (config.preLogger) {
log.info("Global Filter Start: request id -> {}", exchange.request.id)
}
chain
.filter(exchange)
.then(Mono.fromRunnable {
if (config.postLogger) {
log.info("Global Filter End: request id -> {}", exchange.response.statusCode)
}
})
}
class Config {
lateinit var baseMessage: String
var preLogger: Boolean = false
var postLogger: Boolean = false
}
}
spring.cloud.gateway.default-filters:
- name: GlobalFilter
args:
baseMessage: "Spring Cloud Gateway GlobalFilter"
preLogger: true
postLogger: true
로깅 필터
@Component
class LoggingFilter : AbstractGatewayFilterFactory<LoggingFilter.Config>(Config::class.java) {
val log = LoggerFactory.getLogger(LoggingFilter::class.java)!!
override fun apply(config: Config?): GatewayFilter =
OrderedGatewayFilter({ exchange, chain ->
if (config == null) {
throw NullPointerException("config should not be null")
}
log.info("Logging Filter baseMessage: {}", config.baseMessage)
if (config.preLogger) {
log.info("Logging Filter Start: request id -> {}", exchange.request.id)
}
chain
.filter(exchange)
.then(Mono.fromRunnable {
if (config.postLogger) {
log.info("Logging Filter End: request id -> {}", exchange.response.statusCode)
}
})
}, Ordered.LOWEST_PRECEDENCE)
class Config {
lateinit var baseMessage: String
var preLogger: Boolean = false
var postLogger: Boolean = false
}
}
spring.cloud.gateway.routes:
- id: second-service
...
filters:
- name: LoggingFilter
args:
baseMessage: "Spring Cloud Gateway GlobalFilter"
preLogger: true
postLogger: true
로드밸런스 등록
호출순서: 유레카(디스커버리) -> 게이트웨이, Micro Service (First 등)
micro service yaml
server:
port: 0
eureka:
client:
fetch-registry: true
register-with-eureka: true
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
Environment 객체를 이용해서 서버의 포트 번호를 출력할 수 있다.
서버의 포트 번호 출력하기
- Environment 객체
request.serverPort
- HttpServletRequest 객체
env.getProperty("local.server.port")
등록 후의 모습
서버가 다운되면 이렇게 표시된다 ㄷㄷ
'Book & Lecture > 이도원님 MSA' 카테고리의 다른 글
Section 10: Micro Service간 통신 (0) | 2023.06.03 |
---|---|
Section 8: Cloud Bus (0) | 2023.05.28 |
Section 7: Cloud Configuration (0) | 2023.05.24 |
Section 6: User Service (Security in Spring Boot 3.x) (삽질..) (0) | 2023.05.22 |
Section 3 ~ 5 E-Commerse App, User, Catalog, Orders MicroSerivce (0) | 2023.05.22 |
@philo0407 :: Philo의 다락방
hi hello... World >< 가장 아름다운 하나의 해답이 존재한다
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!