본문 바로가기
한화시스템 Beyond SW Camp/백엔드

[Spring Boot] Gateway, Eureka

by taeh00n 2025. 2. 23.

MSA와 Monolithic의 비교 출처 - https://kr.tmaxsoft.com/info/storyTView.do?seq=345

Monolithic Architecture

모든 기능이 하나의 프로젝트 안에 포함되어 한 번에 빌드하고 배포되는 구조

개발과 배포가 단순하지만 서비스가 커질수록 유지보수, 확장이 어려워지고 하나의 기능에 문제가 생기면 서비스 전체에 영향을 줄 수 있는 구조이다.

MSA(Microservices) Architecture

애플리케이션을 작은 단위의 독립적인 서비스로 나눠 개발하고 배포하는 구조

각 서비스가 독립적으로 실행되고 확장될 수 있어서 유연성이 높다. 하지만 서비스 간 통신과 관리를 위해 Spring Eureka와 같은 디스커버리 도구가 필요하다.

 

서비스 디스커버리 (Service Discovery)

서비스 찾기라고 생각하면 된다.

MSA는 위에서 말했다시피 여러 서비스가 각각 실행된다. 예를 들면 Board 서비스는 8081 포트, User 서비스는 8082포트에서 실행된다. Board 서비스가 User 서비스를 이용해야 할 때 서비스가 어딨는지 알아야하는데 서비스가 많아지거나 위치가 바뀌게 되면은 매번 주소를 기억하거나 수정하는 것이 너무 힘들다. 그래서 서비스들이 자동으로 서로를 찾아주게 하는 기능이 바로 서비스 디스커버리이고, 이 역할을 해주는 도구 중 하나가 Spring Eureka가 있다.

 

게이트웨이 (Gateway)

서비들의 관문이라고 생각하면 된다.

사용자가 특정 URL로 요청을 하면은 게이트웨이가 요청 경로(Path)를 보고 적절한 서비스로 연결한다. 


게이트웨이 설정

build.gradle에 게이트웨이 의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-gateway'

application.yml 추가

spring:
  cloud:
    gateway:
      routes:
        - id: board-service
          uri: http://localhost:8081
          predicates:
            - Path=/board/**
        - id: user-service
          uri: http://localhost:8082
          predicates:
            - Path=/user/**
          filters:
            - JwtFilter

id : 각 라우트를 구별하는 이름

uri : 라우팅된 요청을 어디로 보낼지 지정하는 부분

predicates : 어떤 조건일 때 라우트를 사용하는지 정하는 부분.

/board/로 시작하는 경로 요청이면 board-service, /user/로 시작하는 경로 요청이면 user-service

filters: 요청 처리전에 필터링 하는 부분 (인증이나 변환 작업)


Eureka 설정

Eureka 서버 설정

build.gradle에 Eureka Server 의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'

application.yml 추가

spring:
  application:
    name: service-discovery  # 애플리케이션의 이름을 'service-discovery'로 설정

eureka:
  server:
    eviction-interval-timer-in-ms: 60000  # 60초(60000ms)마다 Eureka 서버에서 비정상 인스턴스를 점검함
    renewal-percent-threshold: 0.85  # 85% 이상의 서비스 인스턴스가 갱신되었을 때 갱신된 것으로 판단

  instance:
    hostname: localhost  # Eureka 서버에 등록될 인스턴스의 호스트명을 'localhost'로 설정

  client:
    registerWithEureka: false  # 현재 애플리케이션은 Eureka 서버에 자신을 등록하지 않음
    fetchRegistry: false  # 다른 서비스들의 레지스트리 정보도 Eureka에서 가져오지 않음

Spring Boot 메인 클래스에 @EnableEurekaServer 애노테이션 추가

@EnableEurekaServer
@SpringBootApplication
public class DiscoveryApplication {

    public static void main(String[] args) {
       SpringApplication.run(DiscoveryApplication.class, args);
    }

}

@EnableEurekaServer를 메인 클래스에 추가 후 Spring Boot 애플리케이션을 실행하면 Eureka 서버가 동작한다.


Eureka에 서비스 등록

build.gradle에 Eureka Client 의존성 추가

implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

등록할 서비스의 build.gradle 파일에 Eureka Client 의존성을 추가한다.

application.yml 추가

spring:
  application:
    name: board-api
    
eureka:
  instance:
    lease-renewal-interval-in-seconds: 10  # 10초마다 서비스 인스턴스의 생존 갱신(등록 연장)을 Eureka 서버에 알림.
    lease-expiration-duration-in-seconds: 30  # 30초 동안 갱신이 없으면 서비스 인스턴스가 만료되어 다른 서비스들이 사용할 수 없게 됨.
    prefer-ip-address: true  # 기본적으로 서비스의 IP 주소를 우선시하여 등록 (호스트 이름 대신 IP 주소 사용)
  
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/  # Eureka 서버의 URL을 설정. 이 경우 `localhost:8001`에서 Eureka 서버를 찾음.
    registerWithEureka: true  # 이 애플리케이션을 Eureka 서버에 등록하도록 설정.
    fetchRegistry: true  # Eureka 서버에서 다른 서비스들의 레지스트리 정보를 가져옴.

 

Eureka 접속


Gateway와 Eureka 연동해 URI 동적으로 처리하기

Gateway application.yml 수정

spring:
  cloud:
    gateway:
      routes:
        - id: user-api
          uri: lb://user-api
          predicates:
            - Path=/user/**
        - id: board-api
          uri: lb://board-api
          predicates:
            - Path=/board/**
          filters:
            - JwtFilter

lb:// 로드밸런싱을 이용해서 application.yml 파일을 수정했다. 이렇게 설정을 하게 되면 Eureka에서 등록된 서비스들을 Spring Cloud Gateway가 동적으로 찾아내서 URI 처리를 한다.