이 글은 인프런 강의 "Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)"를 정리한 글입니다. 문제/오류가 있을 시 댓글로 알려주시면 감사드리겠습니다
API Gateway 는 클라이언트 대신 요청, 응답을 해주는 proxy 역할을 한다
시스템 내부 구조는 숨기고 외부 요청에 대해서 적절한 형태로 가공해서 응답할 수 있다는 장점이 있다
API Gateway Service란
인증 권한 부여,
서비스 검색 통합,
응답 캐싱,
정책/회로 차단기 및 Qos 다시 시도,
속도 제한,
로드밸런싱,
로깅/추적/상관관계(ELK를 사용할 수도 있지만 APIGateway를 사용해도 된다),
헤더/쿼리 문자열 및 청구 변환,
IP 허용 목록에 추가
Spring Cloud에서는 MSA간 통신을 할 수 있다
1. RestTemplate
@FeignClient("stores")
public interface StoreClient{
@RequestMapping(method = RequestMethod.GET, value = "/stores")
List<Store> getStores();
}
이전에는 Netflix Ribbon을 이용해 서비스 이름으로 호출, Health Check를 했다
Netflix Zuul
<?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.12.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>11</java.version>
<spring-cloud.version>Hoxton.SR11</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>
package com.example.zuulservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class ZuulServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServiceApplication.class, args);
}
}
package com.example.zuulservice.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@Component
public class ZuulLoggingFilter extends ZuulFilter {
//해당 필터가 실행될 때 수행하는 메소드
//log, 인증정보, 변환작업 등을 여기서 처리할 수 있다
@Override
public Object run() throws ZuulException {
log.info("---------------printing logs: ");
//web 프로젝트에 request/response 정보를 가지고 있는 최상위 객체
RequestContext ctx= RequestContext.getCurrentContext();
//사용자 request 정보 출력
HttpServletRequest request = ctx.getRequest();
log.info("---------------------------: " + request.getRequestURI());
return null;
}
// 이 필터가 무슨 필터인지 반환하는 메소드
@Override
public String filterType() {
return "pre";
}
// 필터의 우선순위를 반환하는 메소드
@Override
public int filterOrder() {
return 1;
}
//필터로 쓸거니까 true
@Override
public boolean shouldFilter() {
return true;
}
}
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
<?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.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>first-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>first-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>Hoxton.SR11</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-eureka-client</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>
//Service2의 경우에는 8082로 설정
server:
port: 8081
spring:
application:
name : my-first-service
eureka:
client:
fetch-registry: false
register-with-eureka: false
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("/")
public class FirstServiceController {
@GetMapping("/welcome")
public String welcome(){
return "Welcome to the First Service";
}
}
first-service/**
는 service1에 요청이 되고, second-service/**
는 service2로 요청이 된다