Spring Cloud 를 이용한 MSA #2. Gateway

Bobby·2023년 2월 7일
0

spring cloud

목록 보기
2/6
post-thumbnail

1. Gateway의 필요성

MOA -> MSA로 전환 되면서 하나의 큰 서버에서 작은 여러개의 서버로 나눠졌다.
클라이언트 입장에서는 각 서버들의 주소를 모두 알고 있기는 어렵다.

그래서 Gateway서버가 필요해 졌다.

Gateway서버는 말그대로 입구이다. 클라이언트는 gateway 서버 주소만 알고 있으면 모든 서비스에 접근이 가능하다. 클라이언트 입장에서는 모놀리틱 서비스와 크게 다르지 않게 느낄 수 있다. 또한 각 서버들을 노출하지 않으므로 보안에도 이점이 있다.

  • 라우팅 기능
  • 서버로의 접근을 차단하거나 제한을 둘 수 있다.
  • 접근에 대한 인증 인가 처리를 할 수 있다.
  • 캐싱 기능
  • 전체 트래픽을 분석하기 용이하다.


2. Spring cloud gateway

  • spring cloud gateway는 비동기 was 인 netty를 사용한다.

  • 멀티모듈로 gateway모듈을 추가 했다.

  • 의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

기본 설정

application.yml

유레카 서버 등록

eureka:
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
    hostname: localhost
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8761/eureka

라우터 등록

server:
  port: 9000 #포트

spring:
  application:
    name: gateway-service #서버 이름
  cloud:
    gateway:
      routes:
        - id: api-service
          uri: lb://API-SERVICE
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*), /$\{segment}

        - id: auth-service
          uri: lb://AUTH-SERVICE
          predicates:
            - Path=/auth/**
          filters:
            - RewritePath=/auth/(?<segment>.*), /$\{segment}
  • 라우팅 할 서버 목록 옵션들을 살펴보자
옵션설명
id라우터 id
url해당서버(유레카에 등록한 서버이름)로 라우팅 한다는 의미(lb는 로드밸런서 사용)
predicates해당 path로 요청이 들어올 경우 라우팅
filters라우팅 하기전 필터를 추가

RewritePath=/api/(?<segment>.*), /$\{segment}
/api/test 로 요청이 들어올 경우 /api/를 빼고 /test 만 전달
로드밸런서는 기본적으로 라운드 로빈을 사용한다.


3. Filter 등록

필터 등록하는 방법을 알아보자.

  • AbstractGatewayFilterFactory를 상속받아 필터를 생성한다.
  • 제네릭 타입에는 설정 파일을 넣어준다.
@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {

	// 설정 객체 주입
    public GlobalFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {

        return (exchange, chain) -> {
        	// http request, response
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            log.info("{}", config.getMessage());

            log.info("Global filter Start: request id -> {}", request.getId());
            log.info("Global request getURI -> {}", request.getURI());

            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("Global filter End: response code -> {}", response.getStatusCode());
            }));
        };
    }

    @Data
    public static class Config { 
        private String message; // 해당 필드들은 application.yml 파일에서 주입
    }
}
  • 필터 추가

application.yml

spring:
 
  ...
 
  cloud:
    gateway:
      default-filters: # 글로벌 필터의 경우 여기에 위치한다.
        - name: GlobalFilter # 생성한 필터 클래스명
          args:
            message: Gateway Global Filter!! # 필터안 설정 객체에 바인딩
      routes:
        - id: test
          uri: lb://API-SERVICE
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*), /$\{segment}
            - name: AuthFilter # 각 서버별로 필터를 적용할 경우 여기에 추가
              args:
                token: test      
      

4. 테스트

  • eureka, gateway, api1, api2 서버를 실행
  • 로드밸런스 테스트를 위해 api 서버를 두개 실행 했다.

요청

http://localhost:9000/api/health_check

  • 게이트웨이 서버로 /api/health_check를 요청하면 API서버로 /health_check 요청
  • 두번 요청하니 api1, api2 사이좋게 한번씩 로그가 찍혔다.

  • gateway server
  • api1
  • api2

전체 코드

https://github.com/haerong22/blog/tree/main/springcloud

profile
물흐르듯 개발하다 대박나기

0개의 댓글