
마이크로서비스 아키텍처의 핵심 원리부터 Spring Cloud 실전 구성까지.
Eureka 서비스 디스커버리, FeignClient 로드밸런싱을 코드와 함께 정리합니다.
프레임워크는 도구일 뿐이다. Spring Boot, Node.js, FastAPI — 어떤 프레임워크를 쓰든 구현해야 하는 기능의 본질은 같다.
💡 앞으로 진행하는 대부분의 프로젝트는 우리 생활의 시스템을 디지털화하는 것이다. 티켓 예매, 환불, 주문 — 결국 그 기능을 코드로 옮기는 일이다.
개발자는 데이터를 저장·가공·제공하는 역할을 담당하는 팀의 한 명이다. 기획, 운영, 서버 관리, 영업 등 다양한 직군과 협력하며 같은 목표를 향해 일한다.
개발로 해결이 어렵다면 운영이나 기획에서 해결책을 찾을 수도 있다. 지속적이고 적극적인 커뮤니케이션도 개발자의 핵심 역량이다.
GPT 같은 AI를 잘 활용해 생산성을 높이는 개발자가 능력 있는 개발자로 평가받는 시대가 됐다. 단, AI에 의존하기 전에 개념을 이해하는 것이 먼저다.
Microservices Architecture(MSA) 는 하나의 애플리케이션을 여러 개의 독립적인 서비스로 분리하여 개발·배포·유지보수를 용이하게 하는 소프트웨어 아키텍처 스타일이다.
각 서비스는 특정 비즈니스 기능을 수행하며, 서비스 간 통신은 주로 HTTP/HTTPS 또는 메시지 큐를 통해 이루어진다.
| 구분 | 모놀리틱 | MSA |
|---|---|---|
| 배포 | 전체를 함께 배포 | 서비스별 독립 배포 |
| 확장 | 전체 애플리케이션을 확장해야 함 | 필요한 서비스만 선택적 확장 |
| 기술 스택 | 단일 스택 | 서비스별 최적 스택 선택 가능 |
| 데이터 | 단일 DB, 일관성 유지 쉬움 | 분산 DB, 일관성 유지 복잡 |
| 복잡도 | 낮음 | 서비스 간 통신 등 복잡도 높음 |
| 팀 구성 | 전체 코드베이스를 함께 관리 | 서비스별 소규모 팀 |
장점
단점
Spring Cloud는 MSA 개발을 위한 스프링 프레임워크의 확장 라이브러리 모음이다.
| 기능 | 모듈 | 설명 |
|---|---|---|
| 서비스 디스커버리 | Eureka | 서비스 인스턴스의 위치를 동적으로 관리 |
| 로드밸런싱 | Ribbon | 클라이언트 사이드 로드밸런서 |
| 서킷 브레이커 | Hystrix / Resilience4j | 장애 전파 차단 및 Fallback 제공 |
| API 게이트웨이 | Spring Cloud Gateway | 라우팅, 인증, 보안 정책 중앙 처리 |
| 설정 관리 | Spring Cloud Config | 중앙 집중식 설정 관리 |
| HTTP 클라이언트 | FeignClient | 선언적 REST API 호출 |
Hystrix는 Netflix가 개발한 서킷 브레이커 라이브러리이며, Resilience4j는 그 대안으로 개발된 경량 Java 라이브러리다.
서킷 상태:
CLOSED → 정상 동작, 모든 요청 통과
OPEN → 장애 감지, 모든 요청 차단 후 Fallback 실행
HALF-OPEN → 일부 요청을 통과시켜 복구 여부 확인
Netflix는 2000년대 후반 DB 장애로 심각한 서비스 중단을 경험했다. 이후 모놀리틱 아키텍처의 한계를 극복하기 위해 MSA 전환을 결정했다.
전환 이유
전환 과정
1. 모놀리식 애플리케이션을 독립적인 마이크로서비스로 분리
2. CI/CD 파이프라인 구축으로 배포 자동화
3. Hystrix, Eureka, Ribbon 자체 개발 후 오픈소스 공개
4. AWS 클라우드 인프라 활용으로 확장성 확보
결과: 수천 개의 마이크로서비스 운영, 글로벌 사용자 증가에 유연하게 대응, 빠른 배포 주기 확보.
MSA에서 각 서비스의 위치(IP, Port)를 동적으로 관리하고 찾아주는 기능이다.
[Client App] → Eureka Server에 서비스 위치 조회
↕
[Service A: :8081] [Service A: :8082]
서비스는 시작 시 Eureka 서버에 자신을 등록(Register) 하고, 다른 서비스는 이를 조회(Discover) 해서 통신한다. Eureka 서버는 주기적으로 헬스 체크를 수행해 응답 없는 인스턴스를 자동으로 제거한다.
의존성 추가 (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/
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 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/ 접속 시 두 인스턴스가 등록된 것을 확인할 수 있다.
서버 사이드 로드밸런싱은 별도의 로드밸런서 서버가 트래픽을 분산하는 방식이고,
클라이언트 사이드 로드밸런싱은 클라이언트(서비스)가 직접 대상 서버를 선택하는 방식이다.
Spring Cloud에서는 Ribbon이 클라이언트 사이드 로드밸런서 역할을 하며, FeignClient와 통합되어 동작한다.
인터페이스와 어노테이션만으로 REST API 호출을 선언적으로 정의할 수 있는 HTTP 클라이언트다.
주요 특징
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(name = "product-service") // Eureka에 등록된 서비스 이름
public interface ProductClient {
@GetMapping("/product/{id}")
String getProduct(@PathVariable("id") String id);
}
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 | 응답 시간이 가장 빠른 서버로 요청 전달 |
구성
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의 핵심을 정리하면 다음과 같다.
Netflix가 직접 개발해 오픈소스로 공개한 Eureka, Ribbon, Hystrix가 Spring Cloud의 핵심이 됐다는 점에서, 실제 대규모 서비스의 고민이 오픈소스 생태계를 만들어 왔음을 알 수 있다.
Copyright ⓒ TeamSparta · 기술 강의노트를 바탕으로 제작된 블로그입니다.