[ MSA ] Spring Cloud Gateway 소개
API Gateway ?
- 사용자 혹은 시스템의 호출을 한 장비에서 일괄적으로 처리할 수 있게 해준다.
프록시의 역할로써, 외부에 내부의 구조를 숨긴다.
사용자의 요청에 따라 적절한 서비스로 요청을 라우팅 해준다.
진입로라고 생각하면 된다.
일괄적 처리
서비스 마다, 동일하게 수행하는 작업을 추출하여 게이트웨이에게 맡길 수 있다.
대표적으로 아래와 같은 기능들에 사용한다.
- 인증과 권한
- 로깅 / 추적 / 상관관계
- 회로차단기
- 캐싱기능
- 서비스 검색 통합
- 부하 분산
- IP 허용 목록에 추가
- 헤더, 쿼리문자열 변환
3. 회로차단기 : 운영 중인 서비스에 문제가 생겼을 경우, 그 경로로 요청이 들어오지 못하게 한다.
보통 응답 캐싱과 함께 사용한다.
게이트웨이가 관리하는 서비스들이 auto-scaling을 할 때, Naming server와 사용하면 관리가 더 용이합니다.
- MSA 서비스들이 auto-scaling을 할 때, 고정 IP가 아닌 경우에, 게이트웨이에서 라우팅 할 서비스의 주소를 하드코딩으로 관리하게 되면 적절하게 서비스를 제공하지 못하게 됩니다.
이런 경우에, Namig Server와 함께 사용하게 되면, 서비스를 주소가 아닌 서비스 이름으로 찾을 수 있게 됩니다.
그래서 동적으로 대상 서비스의 주소가 변경되어도 안정적으로 서비스를 제공할 수 있습니다.
즉, 게이트웨이와 Naming Server를 같이 사용하게 되면, 서비스의 접속정보가 변경되어도
클라이언트와 게이트웨이 모두 요청 정보를 수정하지 않아도 됩니다.
예전에 Restful API를 위해 자주 사용했던, restTemplate과 feign client도 비슷한 차이점을 가지고 있습니다.
restTemplate은 URI를 통해 대상 서버를 인식하고,
feign client는 서비스으 이름을 통해 대상 서버를 인식한다는 차이가 있습니다.
( 정리가 잘 되어있는 사이트 : https://m.blog.naver.com/qjawnswkd/222326922628 )
스프링 클라우드에서 제공하는 API Gateway와 관련된 API는 대표적으로 3가지가 있습니다.
Netflix Zuul / Netflix Ribbon / Spring Cloud Gateway
넷플릭스 사에서 제공한 줄과 리본은 스프링 부트 2.4.x버전 부터 지원을 하지 않게 되었습니다.
이유는 자바 8 부터 제공하는 함수형 인터페이스와 호환이 되지 않아서 입니다.
그래서 Spring Cloud Gateway 로 예시를 소개하도록 하겠습니다.
일단 pom.xml에 다음과 같이 디펜던시를 추가해줍니다.
그리고 application.yml을 설정합니다.
위 설정은 유레카 서버와 연동 하기 전, 게이트웨이만을 통해 라우팅을 하기 위한 설정 예시입니다.
spring.cloud.gateway.routes 에 라우팅 정보를 설정하게 됩니다.
predicates는 url Path와 http Method type 등 여러 정보가 라우팅 조건으로 올 수 있습니다.
uri 는 라우팅 할 서비스의 진입 정보인데, 서비스의 이름이 아닌 주소 정보를 하드코딩으로 설정하였습니다.
spring cloud gateway에서 기본적으로 제공하는 필터들이 있는데, 요청헤더를 추가하거나 응답헤더를 삭제할 수도 있습니다. 위의 예시에서 응답조건을 삭제한 이유는 jwt 토큰을 사용해 요청에 대한 인증을 처리하기 위함인데요.
일반적인 쿠키와 세션을 이용해 사용자 인증을 하는 경우에는 응답 헤더의 쿠키가 필요하지만, jwt 토큰을 사용하는 경우에는 해당 정보가 필요없기 때문에 서버에서 내려주지 않기 위해 설정하였습니다.
여기서, RewritePath 라는 필터를 주목해봅시다.
spring cloud gateway는 라우팅할 주소를 아래와 같이 조합합니다.
들어온 조건 Path = /user-service/**
설정된 라우팅할 uri = http://localhost:8081
spring cloud gateway가 라우팅하는 주소 = http://localhost:8081/user-service/**
이렇게 되었을 때 문제가 무엇일까요??
사용자 서비스의 context path를 user-service로 해주거나, 혹은 Request Mapping 을 위해서 컨트롤러 마다 user-service를 박아줘야 한다는 것입니다.
물론 그렇게 사용할 수도 있겠지만, 이를 해결하기 위해 경로를 재정의 할 수 있는 필터를 사용할 수도 있습니다.
- RewriteHeader=/user-service/(?<segment>.*), /$\{segment}
다음에는 유레카와 연동하여 설정하는 방법을 가져오도록 하겠습니다!