MSA & Spring Cloud 정리

한소연·2026년 3월 16일

내일배움캠프

목록 보기
9/14
post-thumbnail

마이크로서비스 아키텍처의 핵심 원리부터 Spring Cloud 실전 구성까지.
Eureka 서비스 디스커버리, FeignClient 로드밸런싱을 코드와 함께 정리합니다.


목차

  1. 개발자로서 집중해야 할 것
  2. MSA란 무엇인가
  3. Spring Cloud 핵심 모듈
  4. Eureka 서비스 디스커버리
  5. FeignClient & 로드밸런싱

1. 개발자로서 집중해야 할 것

기능에 집중하기

프레임워크는 도구일 뿐이다. Spring Boot, Node.js, FastAPI — 어떤 프레임워크를 쓰든 구현해야 하는 기능의 본질은 같다.

  • 비밀번호는 반드시 암호화해서 저장해야 한다 → 어떤 언어든 해싱 라이브러리를 활용하면 된다
  • 목록은 페이징을 제공해야 한다 → Spring에 페이징이 있으니 다른 프레임워크에도 있거나, 직접 구현하면 된다

💡 앞으로 진행하는 대부분의 프로젝트는 우리 생활의 시스템을 디지털화하는 것이다. 티켓 예매, 환불, 주문 — 결국 그 기능을 코드로 옮기는 일이다.

개발자는 프로젝트의 구성원

개발자는 데이터를 저장·가공·제공하는 역할을 담당하는 팀의 한 명이다. 기획, 운영, 서버 관리, 영업 등 다양한 직군과 협력하며 같은 목표를 향해 일한다.

개발로 해결이 어렵다면 운영이나 기획에서 해결책을 찾을 수도 있다. 지속적이고 적극적인 커뮤니케이션도 개발자의 핵심 역량이다.

AI 도구 활용

GPT 같은 AI를 잘 활용해 생산성을 높이는 개발자가 능력 있는 개발자로 평가받는 시대가 됐다. 단, AI에 의존하기 전에 개념을 이해하는 것이 먼저다.


2. MSA란 무엇인가

정의

Microservices Architecture(MSA) 는 하나의 애플리케이션을 여러 개의 독립적인 서비스로 분리하여 개발·배포·유지보수를 용이하게 하는 소프트웨어 아키텍처 스타일이다.

각 서비스는 특정 비즈니스 기능을 수행하며, 서비스 간 통신은 주로 HTTP/HTTPS 또는 메시지 큐를 통해 이루어진다.

모놀리틱 vs MSA

구분모놀리틱MSA
배포전체를 함께 배포서비스별 독립 배포
확장전체 애플리케이션을 확장해야 함필요한 서비스만 선택적 확장
기술 스택단일 스택서비스별 최적 스택 선택 가능
데이터단일 DB, 일관성 유지 쉬움분산 DB, 일관성 유지 복잡
복잡도낮음서비스 간 통신 등 복잡도 높음
팀 구성전체 코드베이스를 함께 관리서비스별 소규모 팀

MSA 장단점 요약

장점

  • 특정 서비스만 독립적으로 확장해 성능 최적화 가능
  • 다양한 기술 스택 활용으로 서비스별 최적화
  • 서비스별 독립 배포로 빠른 배포 주기 확보
  • 소규모 팀의 민첩한 개발 가능

단점

  • 서비스 간 통신, 데이터 일관성, 트랜잭션 관리 복잡성 증가
  • 모니터링·로깅·장애 대응을 서비스별로 관리해야 해 운영 비용 증가
  • 분산 데이터베이스 환경에서 데이터 일관성 유지 어려움
  • 서비스 간 네트워크 통신으로 지연 시간 발생 가능

3. Spring Cloud 핵심 모듈

Spring Cloud는 MSA 개발을 위한 스프링 프레임워크의 확장 라이브러리 모음이다.

주요 모듈 한눈에 보기

기능모듈설명
서비스 디스커버리Eureka서비스 인스턴스의 위치를 동적으로 관리
로드밸런싱Ribbon클라이언트 사이드 로드밸런서
서킷 브레이커Hystrix / Resilience4j장애 전파 차단 및 Fallback 제공
API 게이트웨이Spring Cloud Gateway라우팅, 인증, 보안 정책 중앙 처리
설정 관리Spring Cloud Config중앙 집중식 설정 관리
HTTP 클라이언트FeignClient선언적 REST API 호출

서킷 브레이커: Hystrix vs Resilience4j

Hystrix는 Netflix가 개발한 서킷 브레이커 라이브러리이며, Resilience4j는 그 대안으로 개발된 경량 Java 라이브러리다.

서킷 상태:
  CLOSED  →  정상 동작, 모든 요청 통과
  OPEN    →  장애 감지, 모든 요청 차단 후 Fallback 실행
  HALF-OPEN → 일부 요청을 통과시켜 복구 여부 확인

실전 사례: Netflix의 MSA 전환

Netflix는 2000년대 후반 DB 장애로 심각한 서비스 중단을 경험했다. 이후 모놀리틱 아키텍처의 한계를 극복하기 위해 MSA 전환을 결정했다.

전환 이유

  • 확장성: 수백만 명 동시 접속을 감당할 인프라 필요
  • 신뢰성: 한 서비스의 장애가 전체에 영향을 주지 않도록
  • 개발 속도: 독립 팀이 동시에 빠르게 기능을 배포

전환 과정
1. 모놀리식 애플리케이션을 독립적인 마이크로서비스로 분리
2. CI/CD 파이프라인 구축으로 배포 자동화
3. Hystrix, Eureka, Ribbon 자체 개발 후 오픈소스 공개
4. AWS 클라우드 인프라 활용으로 확장성 확보

결과: 수천 개의 마이크로서비스 운영, 글로벌 사용자 증가에 유연하게 대응, 빠른 배포 주기 확보.


4. Eureka 서비스 디스커버리

서비스 디스커버리란?

MSA에서 각 서비스의 위치(IP, Port)를 동적으로 관리하고 찾아주는 기능이다.

[Client App] → Eureka Server에 서비스 위치 조회
                        ↕
              [Service A: :8081]  [Service A: :8082]

서비스는 시작 시 Eureka 서버에 자신을 등록(Register) 하고, 다른 서비스는 이를 조회(Discover) 해서 통신한다. Eureka 서버는 주기적으로 헬스 체크를 수행해 응답 없는 인스턴스를 자동으로 제거한다.

Eureka Server 설정

의존성 추가 (build.gradle)

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

ServerApplication.java

@EnableEurekaServer
@SpringBootApplication
public class ServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }
}

application.properties

spring.application.name=server
server.port=19090

# 서버 자신을 유레카에 등록하지 않음
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://localhost:19090/eureka/

Eureka Client 설정

application.yml

spring:
  application:
    name: my-service           # Eureka에 등록될 서비스 이름

eureka:
  client:
    service-url:
      defaultZone: http://localhost:19090/eureka/
    register-with-eureka: true
    fetch-registry: true
  instance:
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 30    # 하트비트 전송 간격
    lease-expiration-duration-in-seconds: 90 # 인스턴스 만료 기간

💡 spring-cloud-starter-netflix-eureka-client 의존성을 추가하고 spring.application.name만 설정해도 Eureka에 자동 등록된다.

실습: Eureka 서버에 인스턴스 2개 연결하기

Eureka Server (:19090)
├── first  (:19091)
└── second (:19092)

first/application.properties

spring.application.name=first
server.port=19091
eureka.client.service-url.defaultZone=http://localhost:19090/eureka/

second/application.properties

spring.application.name=second
server.port=19092
eureka.client.service-url.defaultZone=http://localhost:19090/eureka/

실행 순서: Eureka Server → first → second

http://localhost:19090/ 접속 시 두 인스턴스가 등록된 것을 확인할 수 있다.


5. FeignClient & 로드밸런싱

클라이언트 사이드 로드밸런싱

서버 사이드 로드밸런싱은 별도의 로드밸런서 서버가 트래픽을 분산하는 방식이고,
클라이언트 사이드 로드밸런싱은 클라이언트(서비스)가 직접 대상 서버를 선택하는 방식이다.

Spring Cloud에서는 Ribbon이 클라이언트 사이드 로드밸런서 역할을 하며, FeignClient와 통합되어 동작한다.

FeignClient란?

인터페이스와 어노테이션만으로 REST API 호출을 선언적으로 정의할 수 있는 HTTP 클라이언트다.

주요 특징

  • 인터페이스 기반 선언적 API 호출
  • Eureka 연동으로 서비스 인스턴스 동적 조회
  • Ribbon 통합으로 자동 로드밸런싱 수행

FeignClient 동작 원리

1. Order Service 실행
   → Eureka 서버에서 product-service 인스턴스 목록 조회

2. FeignClient 호출
   → @FeignClient(name = "product-service")

3. Ribbon 로드밸런싱
   → Round Robin으로 3개 인스턴스 중 하나 선택

4. Product Instance 응답
   → 선택된 인스턴스에서 데이터 반환

의존성 설정

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
    implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
}

FeignClient 인터페이스 작성

@FeignClient(name = "product-service")  // Eureka에 등록된 서비스 이름
public interface ProductClient {

    @GetMapping("/product/{id}")
    String getProduct(@PathVariable("id") String id);
}

서비스에서 FeignClient 사용

OrderApplication.java — FeignClient 활성화

@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

OrderService.java

@Service
@RequiredArgsConstructor
public class OrderService {

    private final ProductClient productClient;  // FeignClient 주입

    public String getOrder(String orderId) {
        if (orderId.equals("1")) {
            String productInfo = productClient.getProduct("2");
            return "Your order is " + orderId + " and " + productInfo;
        }
        return "Not exist order...";
    }
}

ProductController.java — 응답 포트 확인용

@RestController
public class ProductController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/product/{id}")
    public String getProduct(@PathVariable String id) {
        return "Product " + id + " info!!!!! From port : " + serverPort;
    }
}

로드밸런싱 알고리즘

알고리즘설명
Round Robin각 서버에 순차적으로 요청 분배. Ribbon 기본값
Weighted서버 성능에 따라 가중치를 부여해 비례적으로 분배
Least Connection현재 연결 수가 가장 적은 서버로 요청 전달
Response Time응답 시간이 가장 빠른 서버로 요청 전달

실습: Order 1개 + Product 3개 로드밸런싱 확인

구성

Eureka Server (:19090)
├── order-service  (:19091)  × 1개
└── product-service           × 3개
    ├── :19092
    ├── :19093
    └── :19094

product-service/application.yml

spring:
  application:
    name: product-service
server:
  port: 19092
eureka:
  client:
    service-url:
      defaultZone: http://localhost:19090/eureka/

IntelliJ에서 같은 ProductApplication을 3개 복사해 VM 옵션으로 포트를 다르게 지정한다.

-Dserver.port=19093
-Dserver.port=19094

order-service/application.yml

spring:
  application:
    name: order-service
server:
  port: 19091
eureka:
  client:
    service-url:
      defaultZone: http://localhost:19090/eureka/

실행 순서: Eureka Server → order-service → product-service (3개)

확인: http://localhost:19091/order/1 에 반복 접속하면 응답의 포트 번호가 19092 → 19093 → 19094로 순환되는 것을 확인할 수 있다.

# 첫 번째 요청
Your order is 1 and Product 2 info!!!!! From port : 19092

# 두 번째 요청
Your order is 1 and Product 2 info!!!!! From port : 19093

# 세 번째 요청
Your order is 1 and Product 2 info!!!!! From port : 19094

이것이 Round Robin 로드밸런싱의 동작이다.


마무리

MSA와 Spring Cloud의 핵심을 정리하면 다음과 같다.

  • MSA는 서비스를 독립적으로 분리해 확장성과 배포 속도를 높이지만, 운영 복잡도가 증가한다
  • Spring Cloud는 MSA에 필요한 디스커버리, 로드밸런싱, 서킷 브레이커 등을 제공한다
  • Eureka는 서비스 위치를 동적으로 관리하는 레지스트리 역할을 한다
  • FeignClient + Ribbon은 선언적 HTTP 호출과 자동 로드밸런싱을 함께 제공한다

Netflix가 직접 개발해 오픈소스로 공개한 Eureka, Ribbon, Hystrix가 Spring Cloud의 핵심이 됐다는 점에서, 실제 대규모 서비스의 고민이 오픈소스 생태계를 만들어 왔음을 알 수 있다.


Copyright ⓒ TeamSparta · 기술 강의노트를 바탕으로 제작된 블로그입니다.

profile
안 되면 될 때까지

0개의 댓글