9/17

졸용·2025년 9월 17일

TIL

목록 보기
77/144

🔹 서비스 디스커버리란?

MSA(Microservices Architecture)나 클라우드 환경에서는 수많은 서비스들이 컨테이너나 VM 위에서 동적으로 실행된다.

이 때, 서비스의 위치(IP, Port) 가 고정적이지 않고, 실행될 때마다 달라질 수 있는데,

클라이언트(또는 다른 서비스)가 특정 서비스를 호출하려면 이 동적으로 변하는 주소를 알아야 한다.

이 문제를 해결하는 게 서비스 디스커버리이다.

쉽게 말해, “서비스가 어디에 있는지 찾아주는 주소록 시스템” 이라고 이해하면 된다



🔹 Eureka란?

Spring Cloud에서 가장 대표적으로 쓰이는 서비스 디스커버리 구현체 중 하나.
(Netflix에서 만든 서비스 디스커버리 서버)

구성 요소는 크게 두 가지이다:
1. Eureka Server: 모든 서비스의 위치 정보를 저장하는 중앙 레지스트리 (등록소)
2. Eureka Client: 자신을 서버에 등록하고, 다른 서비스의 위치를 조회하는 클라이언트 모듈



🔹Eureka, Feign, Ribbon, Resilience4j의 동작 흐름

어제와 오늘 공부한 것을 통합해서 동작 흐름을 정리해보았다.

🔸 각 기술의 역할 요약

  1. Eureka (서비스 디스커버리)
    → 서비스들의 주소(IP/Port)를 등록·조회하는 중앙 서버

  2. Feign Client (Declarative REST Client)
    → @FeignClient 인터페이스만 선언하면, 실제 HTTP 요청을 대신 보내주는 클라이언트
    (즉, RestTemplate의 선언형/자동화 버전이라고 생각하면 됨)

  3. Ribbon (로드밸런서)
    → Eureka에서 가져온 여러 인스턴스 주소 중에서 어느 서버에 보낼지 결정하는 클라이언트 사이드 로드밸런서
    (Spring Cloud 최신 버전에서는 Ribbon 대신 Spring Cloud LoadBalancer 사용)

  4. Resilience4j (서킷 브레이커 라이브러리)
    → 호출 실패나 지연이 발생했을 때 시스템을 보호하는 기능 제공
    (Circuit Breaker, Retry, Rate Limiter, Bulkhead 등의 기능 제공)


🔸 동작 흐름 요약

Order-Service(Feign 호출)
Feign Client(Eureka 조회)
Eureka Server → 서비스 인스턴스 목록 반환
   ↓ (Ribbon 선택)
Ribbon (LoadBalancer)(실제 HTTP 전송)
User-Service (10.0.0.x:port)(응답)
Resilience4j (실패 시 재시도, Circuit Breaker, Fallback)Order-Service

1. Feign Client 호출

@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    UserResponse getUser(@PathVariable Long id);
}
  • OrderService 코드에서 개발자가 userClient.getUser(1L) 호출하면, Feign이 자동으로 HTTP 요청을 준비한다

2. 서비스 주소 조회 (Eureka)

@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/users/{id}")
    UserResponse getUser(@PathVariable Long id);
}
  • Feign은 “user-service”라는 이름만 알고 있음
  • Eureka Server에 등록된 인스턴스 목록을 조회해서 User-Service의 실제 주소(IP, Port)를 가져온다

3. 로드 밸런싱 (Ribbon)

  • Feign은 Eureka에서 받은 인스턴스 리스트를 Ribbon에게 넘김
  • Ribbon이 로드밸런싱 전략(Round Robin, Random 등)에 따라 하나를 선택
    예) 첫 번째 호출 → 10.0.0.1:8081, 두 번째 호출 → 10.0.0.2:8082

4. 실제 HTTP 요청 전송


5. Resilience4j 적용 (장애 대응)

만약 10.0.0.1:8081이 죽어 있다면?

  • Resilience4j의 Retry 정책에 따라 몇 번 재시도
  • 실패가 누적되면 Circuit Breaker가 열려서 더 이상 해당 서버에 요청하지 않음
  • 필요하면 Fallback 메서드로 대체 응답을 내려줌

결과적으로 전체 서비스 장애 확산을 방지



🔸 Eureka와 Ribbon의 차이점

Eureka와 Ribbon의 역할이 비슷해보여 헷갈려서 다시 짚고 넘어가자면, 둘은 관심사가 다르다.

  • Eureka의 역할 (서비스 디스커버리):
    서비스 주소록 = "어디에 있나?"

  • Ribbon의 역할 (로드 밸런서):
    부하 분산 = "누구한테 보낼까?"

예 1)
Eureka: “user-service가 지금 2개 살아 있어 → (10.0.0.1:8081, 10.0.0.2:8082)”
Ribbon: “좋아, 그럼 이번 요청은 10.0.0.2:8082로 보낼게”

예 2)
Eureka = 전화번호부
“피자가게 전화번호 알려줘” → 여러 개 반환

Ribbon = 내가 전화를 걸 때 누구한테 먼저 걸지 정하는 사람
이번에는 1번 지점 전화 걸고, 다음에는 2번 지점 전화 걸고

쉽게 말해,
Eureka = 주소 제공자
Ribbon = 주소 선택자

➡️ Eureka가 ‘목록’을 주고 Ribbon이 ‘선택’을 한다
이렇게 이해하면 깔끔한 것 같다

profile
꾸준한 공부만이 답이다

0개의 댓글