MSA 5일차 - Chap02. Spring Cloud Gateway

Kim Hyen Su·2023년 10월 13일
0
post-thumbnail
post-custom-banner

❓기본지식

프로젝트 생성

  • Group : 도메인 주소(주소이름) - 서비스할 url명
  • Artifact : 프로젝트명

컴포넌트 스캔 & 빈 객체 등록 어노테이션

@Component, @Service, @Repository

  • 기본 어노테이션
  • 가독성을 위해 구분해줌

@Controller(@Component + @RequestMapping)

  • @RequestMapping을 자동으로 포함시켜준다.

@Bean

  • 외부 라이브러리(수정이 불가)를 빈 컨테이너에 등록하기 위해서 @Configuration 어노테이션 안에 빈으로 등록 후 사용해줘야 한다.

실습 세팅

img

Spring Cloud Routung 하위 항목인 Gateway를 선택.

설정용 파일은 yml로 바꾼다.

img

application.yml 파일에 설정을 추가한다.

  • 서버 포트번호 : 8000
  • 게이트웨이 서버를 경유해 연결할 마이크로서비스 서버에 대한 설정은 spring.cloud.gateway.routes를 이용해 서비스명과 uri를 등록.

routes 하위 항목에 대해 설명하자면

  • id : 추후 eureka 서버 등에 등록할 서비스 명을 미리 식별할 수 있도록 부여.
  • uri : 게이트웨이 서버가 아래에 등록할 predicates의 패턴을 감지했을 때 어떤 서버로 포워딩할 지를 지정.
  • predicates : 어떤 조건을 만족할 때 연동된 uri로 보내줄건지 조건 작성(조건문 - 경로, 쿠키, 시간 ...).

일반 프로젝트는 톰캣에 의해 작동한다.

스프링 클라우드 게이트웨이 서버는 Netty에 의해 작동된다.

둘을 조금 더 자세하게 비교하면,

🎇 목적과 사용 사례

Netty :

  • Netty는 비동기 이벤트 기반의 네트워크 애플리케이션을 개발하기 위한 프레임워크.
  • 주로 고성능, 확장 가능한 네트워크 서버를 개발하는 데 사용된다.
  • 보통 웹 서버, 게임 서버, 채팅 서버, 프록시 서버 등과 같은 네트워크 기반의 애플리케이션을 개발하는데 활용된다.

Tomcat :

  • Tomcat은 서블릿(Servlet) 컨테이너로서, JSP와 Servlet 기술을 사용하여 Java 웹 애플리케이션을 실행하는 데 사용된다.
  • 주로 웹 어플리케이션 서버(웹 서버)로서, 웹 애플리케이션을 호스팅하고 관리하는 역할을 한다.
  • 대부분의 Java 웹 애플리케이션은 Tomcat에서 실행된다.

🎇 IO 모델

Netty :

  • Netty는 네트워크 통신에 대한 이벤트 기반의 비동기 IO를 사용한다.
  • NIO(Non-blocking IO)를 기반으로 하여 매우 빠르고 확장 가능한 네트워크 서버를 만들 수 있다.
  • 대용량 데이터를 다루거나 수천 이상의 연결을 처리하는 데 적합.

Tomcat :

  • Tomcat은 전통적인 서블릿 기반의 동기식 IO를 사용.
  • 기본적으로는 스레드 풀을 사용하여 요청당 하나의 스레드를 할당하는 방식이기 때문에, 많은 수의 연결을 동시에 처리하기 어렵다.

🎇 사용하기 쉬운 정도

Netty :

  • Netty는 낮은 수준의 네트워크 프로그래밍을 제공하므로 초기 학습 곡선이 높을 수 있다.
  • 그러나 고급 네트워크 기능을 다루기에 매우 강력하다.

Tomcat :

  • Tomcat은 자바 웹 애플리케이션을 개발하기 위한 표준적이고 간단한 방법을 제공.
  • 대부분의 Java 개발자들이 익숙한 Servlet/JSP 기술을 사용하기 때문에, 배우기 쉽다.

🎇 주요 적용 분야

Netty :

  • 높은 성능이 요구되는 대용량 네트워크 애플리케이션 개발에 적합.
  • 게임 서버, 채팅 서버, 실시간 통신 애플리케이션 등에 많이 사용.

Tomcat :

  • 웹 애플리케이션을 개발하고 호스팅하기 위한 서블릿 컨테이너로 주로 사용.
  • JSP와 Servlet을 사용하는 웹 애플리케이션을 실행하는 데 최적화되어 있다.

🎇 성능 및 확장성

Netty :

  • Netty는 비동기 IO를 사용하여 높은 성능을 제공.
  • 대량의 연결을 효율적으로 처리할 수 있어 확장성이 뛰어나다.

Tomcat :

  • 스레드 기반의 모델을 사용하며, 스레드 당 커넥션을 관리하기 때문에 많은 수의 연결을 동시에 처리하기 어렵다.
  • 따라서 고객의 요구에 따라 클러스터링이나 로드 밸런싱 등을 추가 구현해야 할 수 있다.

🎇 요약:

Netty와 Tomcat은 각각 다른 목적과 특징을 가지고 있다. Netty는 비동기 네트워크 애플리케이션을 개발하는 데 적합하며, 뛰어난 성능과 확장성을 제공한다. 반면 Tomcat은 자바 웹 애플리케이션을 개발하고 실행하기 위한 서블릿 컨테이너로 주로 사용된다.

MicroService의 핵심은 Reverse-Proxy 즉, 마이크로 서비스 서버측이 단일 서버로 보이도록 해주는 것이 중요하다.

실습(마이크로 서비스 2개 붙이기)

🎇 application.yml 로 설정

IntelliJ 에서 Spring Web 프로젝트 2개 생성(first-service, second-service)

img

두 마이크로서비스는 게이트웨이 서버에서 설정할 포트 번호가 8001, 8002로 연결할 예정이기 때문에

실행 포트번호를 아래와 같이 설정한다.

img

접속 가능 여부를 테스트 하기 위해 HelloController 생성 및, RestController 어노테이션을 사용하여 접근이 가능하도록 한다.

img

그 다음으로 게이트웨이, first-service, second-service 각 서버를 실행 해준다.

실행 후 개별 서버로 접속하여 접속 가능 여부를 확인한다.

  • 요청 url : localhost:8001/hello, localhost:8002/hello

그 다음으로 할일은 게이트웨이 서버 하나를 통해서 두 마이크로서비스 서버로 접근이 되도록 application.yml 파일 내 설정을 바꿔준다.

게이트웨이 서버쪽에 application.yml 파일에 localhost:8001 과 8002 관련 주소에 대한 설정을 추가해준다.

img

위 설정을 보면, first-service 라는 아이디의 route는 /first-service/** 라는 요청이 오게되면, 요청에 맞는 uri(컴퓨터 내 자원 주소)인 http://localhost:8001/로 연결해 주겠다는 의미이다.

☢️ 주의 사항

위처럼 설정을 맞춘 뒤 테스트 시 404 오류가 발생함.

  • gateway 서버측 주소(단일점) 를 통해서 마이크로 서비스 서버로 접근해보니, 404 오류가 발생한다.
    • 접근 시 입력 주소 : localhost:8000/first-service/hello
  • gateway 측에서 설정한 마이크로 서비스로 접근할 경로 지정 시,
  • Path=/구분주소명/**
  • 위 처럼 작성해주게 되는데, 이러한 경우 실제 서버에서 요청을 받을 때 컨트롤러에서도 마찬가지로 앞에 '구분 주소명'을 붙여서 요청이 와야 한다.
    • 접근 시 입력 주소 : localhost:8000/hello
    • 실제 마이크로 서비스 서버로 요청되는 url : localhost://8001/first-service/hello
  • 따라서, 마이크로 서비스에 Controller 상에 @RequestMapping 주소로 "first-service" 를 추가해줘야 한다.

img

위처럼 수정 후 게이트웨이 서버의 포트 번호인 8000을 경유하여 접속해도 마이크로서비스 서버로 잘 접속이된다.

img

아래부터 마이크로서비스 서버 접속에 대한 필터 설정과 자바 config 파일로 설정하는 방법에 대해 알아보겠다.

🎇 자바 Config 파일로 설정 및 기본 필터 설정

라우팅 정보를 yml이 아닌 자바 config 클래스로 옮기는 작업을 먼저 해보겠다.

우선, yml 파일에 정의한 내요을 주석을 해준다.

img

그 다음 필터 설정이 들어갈 패키지 및 클래스를 생성.

그 다음으로 아래와 같은 양식으로 작성한다.

img

@Configuration이 붙은 클래스는 빈 컨테이너에 내부에 있는 메서드가 리턴하는 요소들을 적재하는데 @Bean 어노테이션이 붙은 메서드가 리턴하는 객체들을 전부 적재해준다.

설정은 스프링 시큐리티처럼 람다형식으로 설정하면 되는데

img

path() 에는 yml파일에서 Path에 적었던 패턴을 적으면 되고

uri()에는 path()에 적힌 패턴에 걸리면 어떤 서버주소로 포워딩 할 지 정의

filters()에는 이 과정에서 활용할 필터들을 등록하면 된다.

필터 설정

필터는 프록시 형태로 요청 전, 후에 필요한 로직을 추가할 때 사용한다.

필터는 크게 pre-filter와 post-filter로 나뉜다.

pre-fiter : request 처리 전에 실행되는 필터

post-filter : response 처리 전에 실행되는 필터

필요한 로직이 있는 경우 filters에 필터들을 등록해야 한다.

위처럼 람다형식으로 필터 메서드를 add 해주고, 해당 내용을 내부에 작성해준다.

img

2개 이상의 라우터 등록은 위처럼 체이닝 형식으로 route() 메서드를 연결하면 된다.

실제 필터를 거쳐 헤더에 값이 들어오는지 확인

필터를 거치는 요청과 응답 과정

img

위에 그림을 통해 알 수 있듯이, 마이크로서비스 서버 측에서 요청 데이터를 받기 전에 게이트 웨이 서버를 거친 뒤 필터를 거쳐 요청이 들어온다.

이 때, 필터를 거치면서 헤더에 'fsreqh' 라는 키와 'f-req-v'라는 값이 추가된다.

img

마이크로서비스에 header를 확인하기 위한 메서드를 추가한다.

img

위와 같이 헤더의 값을 잘 출력하는 것을 볼 수 있다.

필터 복수개로 등록하는 방법(질문 사항)

🎇 yml 파일에서 필터 적용하기

application.yml 파일에서 필터를 적용하는 방법

게이트웨이 서버측에 자바 config 파일에 @Bean 어노테이션을 비활성화 해준다.

이러면 빈 컨테이너에 해당 메서드가 반환하는 객체가 빈으로 등록되지 않는다. 따라서 설정도 초기화 된다.

img

그리고 yml 파일의 주석을 풀어준다.

그 다음으로 filters라는 항목을 추가해준다.

img

filters에 추가할 항목은 아래와 같다.

  • 필터명=헤더이름,헤더값

추후 커스텀 헤더를 쓸 예정이지만, 우선 디폴트 헤더드들을 이용해보는것이며

위와 같이 작성하면, pre-filter 와 post-filter로 정상 작동하다.

웹 브라우저로 하셔도 좋고, postman으로 진행이 가능하다.

🎇 커스텀 필터 적용하기

커스텀 필터는 AbstractGatewayFilterFactory를 상속한 필터 클래스를 @Component 어노테이션을 이용하여 등록해주면 동작.

생성자에서 super()를 사용하여 apply 라는 메서드 하나를 구현해주면 동작함.

netty 서버에서는 tomcat 서버와는 달리

ServerHttpRequest와 ServletHttpResponse를 사용하고

등록된 필터는 yml 파일에 이름만 기입하면 적용된다.

실습을 진행해보면, AbstractGatewayFilterFactory를 생성해준다. CustomFilter의 이너클래스인 Config를 생성해준다.

해당 이너클래스 안에는 추후 설정 내역을 작성하게 된다.

굳이 이너클래스로 작성한 이유는 코드의 응집도를 높이기 위함이다.

그리고 생성자를 이용해 이너클래스 내역을 super()로 보내준다.

img

그 다음으로 apply(Config config)를 구현해야 한다.

그리고 비동기 서버에서 사용하는 ServerHttpRequest, ServerHttpResponse를 import 한다.

여기서 임포트 구문이 reactive가 포함된 패키지인지 확인해줘야 한다.

pre-filter는 그냥 내부에 작성하면 돌아가는데 반해

post-filter는 아래와 같이 return 구문 안에chain.filter().then(Mono.formRunnable(내부 람다));

를 이용해서 설정할 수 있다.

img

Mono는 스프링 에서 추가되었는데 비동기 방식 서버에서 단일값 전달할 때 사용하는 양식이다.

이제 여기까지 완성시켰다면, yml 파일에 등록해보자.

img

이미 컴포넌트 어노테이션을 통해 등록된 필터 클래스이므로 이름만 적어주면 된다.

참고로 OrderedGatewayFilter를 원래 구현해서 만들어야 하는데 이를 람다로 처리한것이므로

내부 구조가 궁금하다면 OrderedGatewayFilter를 살펴보시는것도 좋습니다.

🎇 전역 필터 적용하기

전역 필터는 위의 AbstractGatewayFilterFactory를 사용하되 등록을 게이트웨이 서버측 자체에 해준다는 차이가 있다.

yml 파일에서의 등록을 gateway 측에 직접 걸어주면 된다.

먼저 GlobalFilter를 새로 작성한다.

어차피 실행하는 기본적인 코드나 원리는 CustomFilter와 비슷하고

단지 차이점은 개별 마이크로서비스에만 적용하는지 gateway 서버에 전역적으로 적용하는지의 차이만 있다.

img

GlobalFilter 라는 클래스를 생성해준다.

다음 설정파일에서 넘겨주는 인자값을 받을 수 있도록 Config 이너 클래스에 멤버 필드들을 선언한다. 그리고 lombok의 @Getter, @Setter를 추가해준다.

img

그리고 해당 정보를 이용해서 글로벌 필터 내부 코드를 작성한다.

img

위 코드에서 상기하고 있어야 할 내용은 pre-filter는 그냥 작성해주면 되고, post-filter는 return 구문 속에 코드를 작성해서 만든다는 점이다.

이후 yml 파일에서 인자 제공 및 필터 등록을 해준다.

위처럼 routes 와 같은 depth 내에 name에는 등록할 전역 필터명을 args 내부에는 Cofnig 이너클래스 멤버변수에서 전달할 값을 입력해주면 된다.

호출 우선순위는

글로벌 pre -> custom pre -> custom post -> 글로벌 post

순으로 마치 스택처럼 호출 및 종료가 이뤄진다.

추후 config 서버를 구성해서 해당 서버만 세팅을 바꿔주고 마이크로서비스 서버는 설정을 바꾸지 않아도 되게 구성할 수 있다.

전역 필터 복수개 적용하기

default-filters:
	- name: GlobalFilter
	  args:
		message:Global Filter Default Message Test
		pre: true
		post: true
	- name: GlobalFilter2
	  args:
		message:Global Filter Default Message Test2
		pre: false
		post: false

위처럼 전역 필터를 여러개 나열하는 방법이다.

🎇 로깅 필터 적용하기

로깅에 좀 더 적합하게 필터를 개선하는 방법

println() 하는 것은 콘솔에 출력만 해주고 실제 로거에 저장 되지는 않는다.

@Slf4j 어노테이션을 추가하여 로거에 로깅을 해준다.

img

별도의 매개변수 없이 필터를 복수로 등록할 경우 아래처럼 나열하면 된다.

로깅필터3

매개변수를 제공하는 경우 아래와 같이 필터별로 - name으로 구분하여 나열해준다.

로깅필터4

profile
백엔드 서버 엔지니어
post-custom-banner

0개의 댓글