코딩공작소
MSA(8) - 게이트웨이를 이용한 서비스 라우팅 본문
게이트 웨이는 무슨 역할을 할까
아키텍처의 모든 마이크로서비스 호출에 대한 필터와 라우터 역할을 서비스로 추상화한다.
즉, 유입되는 모든 트래픽의 게이트키퍼 역할을 수행한다.
서비스 게이트웨이에서 구현할 수 있는 횡단 관심사
- 정적 라우팅 : 단일 서비스 URL과 API 경로로 모든 서비스를 호출
- 동적 라우팅 : 서비스 요청을 검사하고요청 데이터를 기반으로 서비스 호출자를 위한 지능적 라우팅을 수행
- 인증과 인가 : 서비스 호출자가 자신의 인증 여부를 확인할 수 있는 적합한 장소이다
- 지표 수집과 로깅 : 기본 지표를 한곳에서 더욱 잘 수집할 수 있도록 해준다.
서비스웨이 서비스를 위한 구성(컨피그) 서버에 유레카 구성 정보를 추가해야 한다.
server :
port : 8072
eureka :
instance :
preferIpAddress : true
client :
registerWithEureka : true
fetchRegistry : true
serviceUrl :
defaultZone : http://eurekaserver:8070/eureka
그리고 ApiGatewayServerAppication 클래스에 애너테이션을 추가해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package com.optimagrowth.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayServerApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayServerApplication.class, args);
}
}
|
cs |
스프링 클라우드 게이트웨이에서 라우팅 구성
spring:
cloud:
gateway:
discovery.locator: --> 서비스 디스커버리에 등록된 서비스를 기반으로 게이트웨이가 경로를 생성하도록 설정
enabled: true
lowerCaseServiceId: true
스프링 클라우드 게이트웨이는 본래 리버스 프록시이다.
리버스 프록시는 자원에 도달하려는 클라이언트와 자원 사이에 위치한 중개 서버다.
유레카에 새로운 서비스를 추가하면 게이트웨이는 서비스의 물리적 엔드포인트 위치에 대해 유레카와 통신하기 때문에 자동으로 호출을 라우팅할 수 있다.
디스커버리를 통해 명시적으로 경로 매핑을 정의할 수 있어 코드를 더욱 세분화할 수 있다.
spring:
cloud:
loadbalancer.ribbon.enabled: false
gateway:
discovery.locator:
enabled: true
lowerCaseServiceId: true
routes:
- id: organization-service
uri: lb://organization-service
predicates:
- Path=/organization/**
filters:
- RewritePath=/organization/(?<path>.*), /$\{path}
routes : 선택적 ID는 임의의 경로에 대한 ID이며, 경로의 대상 URI를 설정
predicates : 경로는 load()메소드로 설정되지만, 여러 옵션 중 하나
filters : 응답을 보내기 전/후 요청 또는 응답을 수정하고자 web.filters들을 필터링한다.
게이트 웨이 Predicate Factories
요청을 실행하거나 처리하기 전에 요청이 조건 집합을 충족하는지 확인하는 객체로 내장형 값들이 있다.
게이트웨이 Filter Factories
그 중, 사용자 정의 필터가 매우 강력한 기능이라 할 수 있다.
- 사전 필터 : 일반적으로 서비스가 일관된 메시지 형식인지 확인하는 작업. 서비스를 호출하는 사용자가 인증되었는지 확인하는 게이트키퍼 역할
- 사후 필터 : 서비스의 응답을 다시 기록하거나 오류를 처리하거나 민감한 정보에 대한 응답을 검사하려고 사후 필터를 구현
사전 필터
tmx-correlation-id라는 HTTP 헤더의 포함 여부를 확인하는 TrackingFilter라는 사전 필터를 만든다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
package com.optimagrowth.gateway.filters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Order(1)
@Component
public class TrackingFilter implements GlobalFilter {
private static final Logger logger = LoggerFactory.getLogger(TrackingFilter.class);
@Autowired
FilterUtils filterUtils;
@Override --> 요청이 필터를 통과할 때마다 실행되는 코드
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
HttpHeaders requestHeaders = exchange.getRequest().getHeaders();
if (isCorrelationIdPresent(requestHeaders)) {
logger.debug("tmx-correlation-id found in tracking filter: {}. ",
filterUtils.getCorrelationId(requestHeaders));
} else {
String correlationID = generateCorrelationId();
exchange = filterUtils.setCorrelationId(exchange, correlationID);
logger.debug("tmx-correlation-id generated in tracking filter: {}.", correlationID);
}
return chain.filter(exchange);
}
--> 요청 헤더에 상관관계 ID가 있는지 확인하는 헬퍼 메서드
private boolean isCorrelationIdPresent(HttpHeaders requestHeaders) {
if (filterUtils.getCorrelationId(requestHeaders) != null) {
return true;
} else {
return false;
}
}
private String generateCorrelationId() { --> tmx-correlation-id가 있는지 확인하느 헬퍼 메서드이며
return java.util.UUID.randomUUID().toString(); 상관관계 ID를 UUID 값으로 생성한다.
}
}
|
cs |
서비스에서 상관관계 ID사용
- 상관관계 ID는 호출된 마이크로서비스가 쉽게 액세스할 수 있다.
- 마이크로서비스로 수행될 모든 하위 서비스 호출에도 상관관계 ID가 전파된다.
- TrackingFilter는 유입되는 모든 호출에 대해 상관관계 ID를 삽입
- HTTP ServletFilter인 UserContextFilter 클래스는 상관관계 ID를 UserContext 클래스에 삽입. 그 값을 스레드에 저장
- 라이선싱 서비스의 비즈니스 로직은 조직 서비스에 대한 호출을 실행한다.
- RestTemplate은 조직 서비스를 호출하고, UserContextInterceptor를 사용하여 상관관계 ID를 아웃바운드 호출의 HTTP 헤더에 삽입
UserContextFilter 클래스들을 사용하여 유입되는 HTTP요청을 가로챌 수 있수 있으며 서비스에 쉽게 액세스 할 수 있다
상관관계 ID가 있기 때문에 호출과 관련된 모든 서비스를 통과하는 트랜잭션을 추적할 수 있다. 중앙 로그 집계 지점에 기록해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package com.optimagrowth.gateway.filters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import reactor.core.publisher.Mono;
@Configuration
public class ResponseFilter {
final Logger logger =LoggerFactory.getLogger(ResponseFilter.class);
@Autowired
FilterUtils filterUtils;
@Bean
public GlobalFilter postGlobalFilter() {
return (exchange, chain) -> {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
HttpHeaders requestHeaders = exchange.getRequest().getHeaders();
String correlationId = filterUtils.getCorrelationId(requestHeaders);
logger.debug("Adding the correlation id to the outbound headers. {}", correlationId);
exchange.getResponse().getHeaders().add(FilterUtils.CORRELATION_ID, correlationId);
logger.debug("Completing outgoing request for {}.", exchange.getRequest().getURI());
}));
};
}
}
|
cs |
getCorrelationId : 원본 HTTP 요청에 전달된 상관관계 ID를 가져온다
add(FilterUtils.CORRELATION_ID, correlationId) : 응답에 상관관계 ID를 삽입한다
사전 필터에서 데이터를 캡처하는 것과 연관되어 있다면 게이트웨이 사후 필터는 지표를 수집하고 사용자의 트랜잭션과 관련된 모든 로깅을 완료하는 데 이상적인 위치다. 상관관계 ID를 호출자에 다시 전달할 수 있다.
또한, HTTP 응답 헤더에 tmx-correlation-id를 볼 수 있다.
- 필터를 사용하면 들어오고 나가는 HTTP 요청과 응답을 수정할 수 있다
- 게이트웨이는 넷플릭스의 유레카 서버와 통합되며, 오레카에 등록된 서비스를 자동으로 경로에 매핑할 수 있다.
- 애플리케이션의 구성 파일에서 수동으로 경로 매핑을 정의할 수 있다
- 필터로 사용자가 정의한 비즈니스 로직을 구현할 수 있으며 사전/사후 필터를 생성할 수 있다.
- 모든 서비스 호출에 주입할 수 있는 상관관계 ID를 생성할 수 있다
- 모든 HTTP 서비스 응답에 상관관계 ID를 삽입할 수 있다
'어플리케이션개발 > MSA' 카테고리의 다른 글
MSA(10) - 스트림을 사용한 이벤트 기반 아키텍처 (0) | 2024.07.25 |
---|---|
MSA(9) - 마이크로서비스 보안 (0) | 2024.07.22 |
MSA(7) - Resilience4j를 사용한 회복성 패턴 (1) | 2024.07.14 |
MSA(6) - 서비스 디스커버리 (0) | 2024.07.08 |
MSA(5) - 스프링 클라우드 컨피그 서버 구성관리 (0) | 2024.07.03 |