[Spring Cloud Gateway] Load Balancer
이번에는 Spring Cloud Gateway와 Eureka 서버를 연동해보자.
유레카라는 네이밍 서비스에 스프링 게이트웨이를 등록하고,
first-service
와 second-service
까지 등록해보자.
🙂 Spring Cloud Gateway
- Eureka
연동
개요
- 예를 들어, 클라이언트가
http://localhost:8000/first-service/**
에 요청할 때 - 이 요청정보가 유레카 서버에 전달되고
- 유레카로부터 그 요청을 처리할 수 있는 마이크로 서비스의 위치 정보를 전달 받고
- 게이트웨이 서비스가 해당 요청을 해당 마이크로 서비스로 포워딩한다.
코드
1) apigateway-service
pom.xml
유레카 클라이언트를 등록하자.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
유레카 클라이언트는 first-service
와 second-service
모두 추가해준다.
application.yml
유레카 클라이언트 설정을 true
로 변경하자.
이는 “8761번 포트(discovery-service
)에 유레카 클라이언트로 등록하겠다”는 의미이다.
...
eureka:
client:
register-with-eureka: true # 🌟 변경
fetch-registry: true # 🌟 변경
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
cloud:
gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage: Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
routes:
- id: first-service
uri: lb://MY-FIRST-SERVICE # 🌟 uri 변경
predicates:
- Path=/first-service/**
filters:
- CustomFilter
- id: second-service
uri: lb://MY-SECOND-SERVICE # 🌟 uri 변경
predicates:
- Path=/second-service/**
filters:
- name: CustomFilter
- name: LoggingFilter
args:
baseMessage: Hi, there.
preLogger: true
postLogger: true
spring.cloud.gateway.routes
에서,
first-service
의 uri
는 원래 http://localhost:8081/
이었고,
second-service
의 uri
는 원래 http://localhost:8082/
이었다.
이것을 lb://MY-FIRST-SERVICE
와 lb://MY-SECOND-SERVICE
로 바꿈으로써,
기존처럼 http 프로토콜을 이용해 localhost:8081
혹은 localhost:8082
로 가는게 아니라,
클라이언트의 요청 정보를 유레카 서버에게 전달하겠다는 의미이다.
2) first-service
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml
...
eureka:
client:
register-with-eureka: true # 🌟 변경
fetch-registry: true # 🌟 변경
service-url:
defaultZone: http://localhost:8761/eureka
3) second-service
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml
...
eureka:
client:
register-with-eureka: true # 🌟 변경
fetch-registry: true # 🌟 변경
service-url:
defaultZone: http://localhost:8761/eureka
이로써 총 3개의 서비스가 유레카 서버(discovery-service
)에 등록된 것이다.
apigateway-service
: 8000번 포트first-service
: 8001번 포트second-service
: 8002번 포트
서버 기동
유레카 서버(discovery-service
)를 먼저 기동시킨 후,
게이트웨이(apigateway-service
), first-service
, second-service
순으로 기동시키자.
이제 http://localhost:8761
(= 유레카 서버)에 접속하면 3개의 서비스가 등록된 것을 확인할 수 있다.
포스트맨 결과
이를 통해, 기존에 http://localhost:8081
혹은 http://localhost:8082
로 호출했던 정보들을
유레카 서버에 있는 위치로 정보를 변경하더라도 (lb://MY-FIRST-SEVICE
, lb://MY-SECOND-SEVICE
)
정상적으로 작동하는 것을 확인할 수 있다.
여기까지 하면, 이제 하나 이상의 마이크로 서비스를 기동해서 로드 밸런서의 기능을 구현할 수 있는 것이다.
이제 이것을 테스트해보자.
🙂 first-service
와 second-service
를 각각 2개씩 기동
- 방법 1
- 인텔리제이에서Edit Configurations
-> VM options에-Dserver.port=9003
입력 - 방법 2
- 터미널에mvn spring-boot:run -Dspring-boot.run.jvmArguments='-Dserver.port=9003'
커맨드 입력 - 방법 3
- 패키지 파일 생성 후 java 명령어로 해당 패키지 파일 실행mvn clean compile package # maven 빌드 java -jar -Dserver.port=9003 ./target/uesr-service-0.0.1-SNAPSHOT.jar
연습을 위해 first-service
와 second-service
를 각각 다른 방법으로 2개씩 기동해보자.
first-service
는 방법 1을 이용했고, second-service
는 방법 3을 이용했다.
first-service
second-service
이로써 유레카 서버(discoveryservice
)에는 아래 사진에서 볼 수 있듯이,
게이트웨이 서비스(apigateway-service
)와 4개의 마이크로 서비스(first-service
2대, second-service
2대)가 등록된 상태이다.
그런데, apigateway-service
의 application.yml
을 보면 아래와 같다.
위 사진에서 lb://MY-FIRST-SERVICE
는
/first-service/**
로 요청이 들어오면 디스커버리 서비스(= 네이밍 서비스) 안에 등록되어있는 서비스들 중,
이름이 MY-FIRST-SERVICE
인 서비스로 보내겠다는 의미인데, MY-FIRST-SERVICE
서비스 안에는 2개의 인스턴스가 있다.
이 때, 9091
로 갔는지 8081
로 갔는지 어떻게 알 수 있을까?
랜덤포트 사용
first-service
copy 한 FirstServiceApplication(1)
은 삭제하고 application.yml
을 아래와 같이 변경한다.
server:
port: 0 # 🌟 8081에서 0으로 변경
spring:
application:
name: my-first-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
instance: # 🌟 추가
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
first-service
하나 더 기동
터미널을 이용해 first-service
를 하나 더 기동해보자.
mvn spring-boot:run
랜덤포트를 사용하기 때문에 뒤에 옵션으로 포트번호를 지정할 필요가 없다.
결과
어떤 서비스가 실행될 때 몇 번 포트가 사용되었는지 출력
first-service
FirstServiceController.java
@RestController
@RequestMapping("/first-service")
@Slf4j
public class FirstServiceController {
Environment env;
@Autowired
public FirstServiceController(Environment env) {
this.env = env;
}
@GetMapping("/check")
public String check(HttpServletRequest request) {
log.info("server port={}", request.getServerPort());
return String.format("Check First Service on PORT %s", env.getProperty("local.server.port"));
}
}
스프링에서는 @Autowired Environment env;
으로 변수에 직접 주입받는 것보다는,
위 코드에서처럼 생성자를 통해 주입받는 것을 권장한다.
request
에서 포트 번호를 가져올 수도 있고, 환경변수에서 가져올 수도 있다.
포스트맨 테스트
인텔리제이에서 run
버튼을 클릭하고, 터미널에서 mvn spring-boot:run
커맨드를 입력해
first-service
를 총 2대 기동한 후에 포스트맨에서 테스트 해보자.
포스트맨에서 http://localhost:8000/first-service/check
에 접속해보자.
첫 번째 호출
두 번째 호출
이와 같이, Round Robin 방식으로,
한 번은 인텔리제이의 마이크로 서비스로, 또 한 번은 터미널의 마이크로 서비스로 번갈아가며 호출을 해준다.
따라서 게이트웨이를 사용하면, 라우팅 기능과 로드 밸런싱 기능을 사용할 수 있다.
💛 개인 공부 기록용 블로그입니다. 👻