본문 바로가기
Framework/Spring Boot

[Spring Boot] Eureka 서비스 디스커버리

반응형

마이크로서비스 아키텍처(MSA)를 도입하고 API Gateway까지 앞에 세웠습니다. 이제 클라이언트의 모든 트래픽은 Gateway가 yml 설정에 적힌 IP(192.168.0.10:8082)를 보고 주문 서버로 넘겨줍니다. 그런데 오늘 블록버스터급 할인 이벤트가 터지면서 주문 서버 CPU가 99%를 치기 시작했습니다! 다급해진 인프라 팀이 AWS 오토스케일링(Auto Scaling)을 돌려 주문 서버를 순식간에 5대로 늘렸습니다. 새로 켜진 서버 4대는 각자 랜덤한 새 IP(예: 192.168.0.11 ~ 14)를 발급받았습니다. 자, Gateway는 새로 켜진 4대의 서버 IP를 어떻게 알고 트래픽을 골고루 나눠줄(Load Balancing) 수 있을까요? yml 파일에 직접 적혀있지 않으니 Gateway는 새 서버들의 존재조차 모릅니다. 매번 서버가 늘어날 때마다 사람이 Gateway의 설정을 고치고 재시작해야 할까요? 이 '동적인 IP 주소 관리' 문제를 완벽하게 해결해 주는 넷플릭스(Netflix)의 천재적인 오픈소스, Eureka(유레카) Service Discovery가 등장합니다.

이번 [Spring Boot 실무 완벽 가이드] 시리즈에서는 "MSA의 살아 움직이는 전화번호부!" Eureka Server 구축과 클라이언트 연동 실무에 대하여 다뤄보겠습니다.

📖 1. Eureka의 핵심: 전입신고와 전화번호부

개념은 구청의 전입신고와 똑같습니다.

Eureka 개념도
  • Eureka Server (전화번호부 관리자): 중앙에 우두커니 떠 있는 하나의 독립된 스프링 부트 서버입니다. 누가 살아있는지 리스트만 관리합니다.
  • Eureka Client (각종 마이크로서비스들): '주문 서버', '회원 서버' 같은 녀석들입니다. 얘네들은 서버가 딱 켜지는 순간, Eureka Server에 찾아가서 "제 애플리케이션 이름(spring.application.name)은 ORDER-SERVICE고요, IP는 이거예요!" 하고 전입신고를 합니다. 그리고 30초마다 "나 아직 안 죽고 살아있어~" 라며 심장 박동(Heartbeat) 신호를 보냅니다.

만약 주문 서버 중 1대가 에러로 뻗어서 심장 박동이 끊기면, Eureka Server는 "어? 얘 죽었네. 전화번호부에서 삭제(Evict)!" 해버립니다.


⚙️ 2. Gateway의 진화: IP가 아닌 '이름'으로 찾기

이제 가장 중요한 Gateway의 변화입니다. 이전 단계에서 Gateway는 uri: http://192.168.0.10:8082 처럼 IP를 하드코딩했습니다. 하지만 Gateway도 Eureka Client로 등록해 두면, 놀라운 마법이 일어납니다.

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          # 🌟 핵심! 더 이상 http://IP가 아니라 lb://(애플리케이션이름) 을 사용합니다!
          uri: lb://ORDER-SERVICE 
          predicates:
            - Path=/order/**

lb://ORDER-SERVICE의 의미는 이렇습니다. "Eureka 전화번호부에서 ORDER-SERVICE라는 이름을 가진 서버들의 IP 리스트를 다 가져와. 그중에서 안 바쁜 서버 하나 골라서(Load Balancing, lb) 트래픽을 넘겨줘!"
이제 서버가 100대로 늘어나든, 죽어서 1대로 줄어들든 Gateway 설정은 단 한 글자도 바꿀 필요가 없습니다. 모든 것이 완벽하게 자동화되었습니다.


💀 3. MSA의 그림자: 분산 시스템의 복잡성

Gateway와 Eureka를 조합하여 IP를 모르더라도 동적으로 라우팅하는 완벽한 MSA 트래픽 인프라가 완성되었습니다. 하지만 이 아름다운 MSA 아키텍처 이면에는 아주 무서운 그림자가 존재합니다.

만약 '회원 서버'에 문제가 생겨서 DB 조회가 10초씩 걸리기 시작했다고 가정해 봅시다. 클라이언트가 Gateway를 통해 '주문 서버'에 요청을 보냅니다. '주문 서버'는 사용자의 등급을 알기 위해 내부적으로 '회원 서버'를 호출합니다(Feign Client 등). 회원 서버가 응답을 안 하니 주문 서버도 10초 동안 대기(Blocking)합니다. 주문 서버가 대기하니 그 앞의 Gateway도 10초 대기합니다! 결국 회원 서버 하나가 아픈 것뿐인데, 도미노가 쓰러지듯(Cascading Failure) 전체 쇼핑몰의 모든 서비스가 올스톱되는 대참사가 벌어집니다.


🎯 4. 마무리 및 다음 단계

지금까지 수시로 IP가 바뀌는 클라우드 환경에서 하드코딩의 저주를 풀고, 마이크로서비스들이 자율적으로 전입신고를 하며 lb://이름 기반의 다이내믹 라우팅(Dynamic Routing)을 완성하는 Eureka Service Discovery의 아키텍처에 대해 상세히 다루어 보았습니다. 이제 진정한 클라우드 네이티브(Cloud Native) 환경에 한 발짝 다가섰습니다.

그런데 방금 언급한 '도미노 붕괴(Cascading Failure)' 현상은 MSA에서 회사가 망할 수도 있는 가장 치명적인 약점입니다. 회원 서버가 죽었으면, 주문 서버는 회원 서버를 기다리다 같이 죽지 말고 "어? 회원 서버 아프네? 기다리지 말고 그냥 비회원 취급해서 빨리 결제나 넘겨버려!"라며 연결(회로)을 스스로 끊어버려야(차단) 합니다. 이어지는 39단계 포스팅에서는 "장애가 번지는 것을 물리적으로 끊어버리는 MSA 최후의 방어막!" Resilience4j(리질리언스4j)를 활용한 서킷 브레이커(Circuit Breaker) 패턴과 Fallback 실무 가이드에 대해 아주 뼈 때리게 파헤쳐 보겠습니다!

반응형