반응형
API Gateway란
- API Gateway란 여러 마이크로 서비스들과 통신하기 위한 단일 지점(진입로)으로 모든 요청에 대해서 일괄적으로 처리해준다. Gateway는 인증 및 권한 체크, 응답 캐싱, 부하 분산 등의 역할을 수행한다.
Spring Cloud 에서 MSA 간 통신
RestTemplate
RestTemplate restTemplate = new RestTemplate();
restTemplate.getForObejct("url", Domain.class, 200);
RestTemplate
을 통해 MSA url을 기반으로 통신하는 방법이다.
Feign Client
@FeignClient("test")
public interface TestClient {
@RequestMapping(method = RequestMethod.GET, value = "/test")
List<Domain> getDomains();
}
- 스프링 클라우드에서 제공하는 feign client 어노테이션을 이용해서 서버의 주소 없이 MSA명으로 호출할 수 있다.
Netflix Ribbon
- Ribbon은 클라이언트 사이드에서 로드밸런싱 역할을 해준다. 즉, 별도의 게이트웨이 없이 클라이언트 단에서 Ribbon을 통해 통신을 한다. 단, SPA와 같은 비동기 통신에 호환이 잘 되지 않는다.
Netflix Zuul
- 클라이언트 단에서 사용되는 Ribbon과 다르게 API Gateway 역할을 하는 Netflix 사의 제품으로 Routing 기능을 제공한다.
Netflix 사에서 제공한 라이브러리는 SpringBoot 2.4에서 부터 Maintenance 상태이므로 사용하고 싶은 경우 버전 다운그레이드를 해야한다.
Neflix Zuul
- Zuul Architecture는 다음과 같다. HttpServlet을 상속받은 ZuulServlet과, ZuulFilter를 통한 Runner 실행 등을 제공한다.
Zuul 라이브러리를 사용해보자. 서비스는 First Service, Second Service, Zuul Service로 구성되어있다.
Zuul Service
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>zuul-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>zuul-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- Zuul 사용 시 반드시 SpringBoot 2.4 버전 미만을 사용해야하며,
Spring Web
,Lombok
,Zuul
라이브러리를 주입 받았다.
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
@EnableZuulProxy
어노테이션을 주입하자.
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
- application.yml 에는 포트 정보와, zuul 라우팅 처리를 해주자. 참고로 라우팅하는 서비스 명은 프로젝트 생성 시
artifactId
를 따라간다.
Service
server:
port: 8081
spring:
application:
name: my-first-service
eureka:
client:
fetch-registry: false
register-with-eureka: false
- First Service와 Second Service는
Spring Web
,Lombok
,Cloud Discovery Client
를 주입받고 필요한 설정을 해주었다.
- 다음과 같이 Zuul 서버 단에서 서비스 명을 통해 접근할 수 있다.
Spring Cloud Gateway
Netflix 라이브러리가 2.4부터 지원하지 않게 되면서, Spring Cloud 상에서 Spring Cloud Gateway를 사용하게 끔 되었다. Lombok
과 Spring Cloud Routing 에서 Gateway
, Eureka client
를 의존성 주입하고 프로젝트를 생성하자.
server:
port: 8000
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
uri: http://localhost:8081
predicates: # 조건절
- Path=/first-service/**
- id: second-service
uri: http://localhost:8082
predicates: # 조건절
- Path=/second-service/**
- application.yml 파일에 다음과 같이 지정하고 프로젝트를 실행해보자. 기존 Zuul 방식과 다르게 로그를 살펴보면
Netty started on port 8000
가 출력되는 것을 볼 수 있다. Zuul은 동기화 방식을 사용하기 때문에 톰캣을, API Gateway는 비동기 방식을 사용하기 때문에 Netty를 사용한다.
- 기존에 성공했던 url을 실행해보면 404 상태코드가 발생한다. path를 살펴보면 기존에 서비스명이 포함돼서 들어가는 것을 볼 수 있다. 즉 gateway 서버로부터
http://localhost:8081/first-service/welcome
이 호출된 것이다. - predicates 조건절 뒤에 Path는 uri에 그대로 붙는다는 점을 주의해서 클라이언트 단에서 설계하자.
package com.example.firstservice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/first-service")
public class FirstServiceController {
@GetMapping("/welcome")
public String welcome() {
return "Welcome to the First Service";
}
}
- client 단의 Request URL을
/
에서/first-service
로 변경해보자.
- 정상적으로 리턴되는 것을 확인할 수 있다.
Zuul vs Spring Cloud Gateway
- Servlet API와 같은 동기식 라이브러리를 사용하는 경우가 많을 경우 Zuul을 사용하는 것이 유리하다. (단, SpringBoot 2.4 이전 버전만 사용 가능, Zuul 2.0 부터 비동기 기능도 제공한다.)
- WebFlux 등을 사용해서 비동기식 필터링을 처리하는 경우 Spring Cloud API Gateway를 사용하는 것이 좋다. (버전의 문제가 없다.)
- Filter의 경우 webflux를 지원하는
WebFilter
를 구현하여 사용할 수 있다.
- Filter의 경우 webflux를 지원하는
REFERENCE
https://cloud.spring.io/spring-cloud-netflix/reference/html/
반응형