NYO_O

MSA 환경에서 서비스 디스커버리(Service Discovery)가 필요한 이유 본문

Architecture/MSA

MSA 환경에서 서비스 디스커버리(Service Discovery)가 필요한 이유

NYO_O 2026. 5. 26. 20:23
반응형

정적 IP 기반 라우팅의 한계

지난 포스팅에서는 거대한 모놀리식 시스템을 여러 개의 독립적인 서비스로 분리하는 마이크로서비스 아키텍처(MSA)의 개념과 도입 배경을 다루었습니다. 하지만 시스템을 분산 환경으로 전환하는 순간, 개발자들은 '서비스 간 통신 및 라우팅'이라는 새로운 인프라적 과제에 직면하게 됩니다.

2026.05.20 - [Tech/MSA] - 모놀리식의 한계와 마이크로서비스 아키텍처(MSA)의 등장 배경

 

모놀리식의 한계와 마이크로서비스 아키텍처(MSA)의 등장 배경

초기 서비스 개발 단계에서는 모든 비즈니스 로직을 하나의 프로젝트로 구성하는 것이 일반적입니다. 하지만 서비스 규모가 성장하고 도메인이 복잡해지면서, 단일 코드베이스는 점차 관리하

ddangnyo.tistory.com

과거 온프레미스(On-Premise) 물리 서버 환경에서는 서버의 IP 주소가 고정되어 있었습니다. 따라서 주문 서비스가 결제 서비스와 통신해야 할 경우, 설정 파일(yaml, properties 등)에 결제 서버의 정적 IP를 하드코딩해 두는 방식으로 통신 채널을 구성할 수 있었습니다.

하지만 클라우드 네이티브(Cloud Native) 환경과 도커(Docker), 쿠버네티스(Kubernetes) 등 컨테이너 오케스트레이션 도구가 주도하는 현대의 MSA 인프라에서는 상황이 완전히 다릅니다. 오토 스케일링(Auto Scaling)에 의해 트래픽 부하에 따라 컨테이너 인스턴스가 수시로 생성되고 소멸하며, 이 과정에서 내부 IP 주소는 런타임에 동적으로 재할당됩니다. 이렇게 수시로 네트워크 위치가 변하는 환경에서는 기존의 정적 IP 하드코딩 방식으로는 서비스 간 통신을 유지할 수 없습니다.

서비스 디스커버리(Service Discovery) 아키텍처

이러한 동적 네트워크 환경의 문제를 해결하기 위해 도입된 아키텍처 패턴이 바로 '서비스 디스커버리(Service Discovery)'입니다.

서비스 디스커버리는 네트워크 상에 흩어져 있는 각 마이크로서비스 인스턴스들의 메타데이터(서비스 이름, IP 주소, 포트 번호 등)를 중앙 집중적으로 관리하는 레지스트리(Registry) 서버를 구축하는 것을 의미합니다.

이 패턴을 적용하면 클라이언트 서비스는 타겟 서비스의 물리적인 IP 주소를 알 필요가 없습니다. 오직 통신하고자 하는 서비스의 논리적인 '이름(Service ID)'만 알고 있다면, 중앙의 서비스 레지스트리를 조회하여 현재 통신 가능한 실제 IP 주소 목록을 동적으로 획득할 수 있습니다. 이를 통해 인프라의 변동성과 애플리케이션의 라우팅 로직을 완벽하게 분리하는(Decoupling) 효과를 얻게 됩니다.

서비스 디스커버리의 3가지 핵심 메커니즘

서비스 디스커버리 아키텍처는 항상 최신의 네트워크 상태를 유지하기 위해 크게 세 가지 핵심 프로세스로 동작합니다.

첫 번째는 서비스 등록(Service Registration)입니다. 새로운 마이크로서비스 인스턴스가 부팅될 때, 해당 인스턴스는 가장 먼저 서비스 레지스트리 서버에 자신의 논리적 이름과 할당받은 네트워크 주소(IP, Port)를 전송하여 명부에 등록합니다.

두 번째는 서비스 조회(Service Resolution/Fetch)입니다. 다른 서비스와 통신이 필요한 클라이언트 서비스는 API 요청을 보내기 직전, 서비스 레지스트리에 타겟 서비스의 이름을 질의하여 현재 가용한 IP 목록을 응답받습니다. (이 응답 데이터는 네트워크 부하를 줄이기 위해 보통 클라이언트 측에 로컬 캐싱됩니다.)

세 번째는 헬스 체크(Health Check) 및 상태 동기화입니다. 서비스 레지스트리에 등록된 인스턴스에 장애가 발생해 비정상 종료될 경우, 레지스트리가 이를 인지하지 못하면 클라이언트에게 잘못된(죽은) IP를 제공하여 통신 장애(Connection Refused)를 유발하게 됩니다. 이를 방지하기 위해 각 인스턴스들은 레지스트리를 향해 주기적으로 하트비트(Heartbeat) 신호를 보냅니다. 만약 설정된 임계치 시간 동안 하트비트가 수신되지 않으면, 레지스트리는 해당 인스턴스를 가용 목록에서 즉각 제외(Eviction)하여 라우팅 안정성을 보장합니다.

Spring Cloud Eureka의 역할과 특징

자바(Java) 기반의 Spring Boot 생태계에서 이러한 서비스 디스커버리 패턴을 구현하기 위해 가장 보편적으로 사용되는 도구는 넷플릭스 OSS(Netflix OSS)에서 출발한 'Spring Cloud Eureka'입니다.

Eureka는 구성이 매우 직관적입니다. 레지스트리 역할을 할 서버 프로젝트에 @EnableEurekaServer 어노테이션을 부여하면 즉각적으로 서비스 디스커버리 서버가 구동됩니다. 그리고 연동될 각 마이크로서비스들에 @EnableDiscoveryClient 어노테이션을 설정하면, 부팅 시점에 자동으로 유레카 서버에 자신의 메타데이터를 등록하는 클라이언트로 동작하게 됩니다.

Eureka는 특히 CAP 정리(CAP Theorem) 측면에서 AP(Availability, 가용성 및 Partition tolerance, 분할 내성) 시스템에 가깝게 설계되어 있습니다. 일시적인 네트워크 단절로 인해 레지스트리 서버 간의 완벽한 데이터 일치성(Consistency)이 조금 깨지더라도, 클라이언트가 캐싱된 라우팅 정보를 기반으로 단절 없이 지속적으로 통신할 수 있도록 가용성을 극대화하는 특징을 가집니다.

Eureka 외의 대안

  • HashiCorp Consul (콘설): 자바 생태계에 종속적인 Eureka와 달리, Go, Python, Node.js 등 다양한 언어로 구성된 폴리글랏(Polyglot) 환경에서 범용적으로 사용하기 좋습니다. 서비스 디스커버리 기능뿐만 아니라 분산 Key-Value 저장소와 강력한 헬스 체크 메커니즘을 내장하고 있어 엔터프라이즈 환경에서 널리 채택됩니다.
  • Apache ZooKeeper (주키퍼): 분산 시스템의 코디네이터로 오랜 기간 검증된 솔루션입니다. 카프카(Kafka) 등과 연동되어 많이 사용되었으나, 시스템 자체가 무겁고 관리가 까다로워 최근에는 순수 서비스 디스커버리 목적만으로는 도입을 지양하는 추세입니다.

Kubernetes 환경의 Server-Side Discovery

최근 마이크로서비스 생태계에서 가장 주목해야 할 인프라적 변화는 '쿠버네티스(Kubernetes)'의 대중화입니다.

과거에는 애플리케이션 코드(Spring Boot) 내부에서 Eureka 같은 클라이언트 라이브러리를 통해 IP를 조회하고 라우팅하는 '클라이언트 사이드 디스커버리(Client-Side Discovery)' 방식이 주류였습니다. 하지만 쿠버네티스 환경에서는 인프라 플랫폼 자체가 강력한 서비스 디스커버리 기능을 내장하고 있습니다.

쿠버네티스의 Service 리소스와 내부 CoreDNS를 활용하면, 개발자는 애플리케이션 코드에 별도의 레지스트리 설정이나 디스커버리 라이브러리를 포함할 필요가 전혀 없습니다. 주문 서비스가 결제 서비스와 통신할 때 단순히 내부 DNS 이름(예: http://payment-service)으로 HTTP 요청을 보내기만 하면, 쿠버네티스의 인프라 계층(Kube-proxy)에서 알아서 가용한 파드(Pod)의 IP로 트래픽을 찾아 연결해 줍니다.

이를 '서버 사이드 디스커버리(Server-Side Discovery)'라고 부르며, 비즈니스 로직과 인프라 라우팅 로직을 완벽하게 분리할 수 있다는 점에서 현대 클라우드 네이티브 아키텍처의 표준으로 굳어지고 있습니다.

마무리

오늘은 MSA의 동적인 인프라 환경에서 발생하는 IP 변동 문제를 해결하기 위한 서비스 디스커버리의 개념과 핵심 메커니즘, 그리고 쿠버네티스 환경에서의 패러다임 변화까지 알아보았습니다. 레지스트리와 내부 DNS를 도입함으로써 애플리케이션은 물리적인 인프라 종속성에서 벗어나 유연한 확장이 가능해졌습니다.

그런데 여기서 새로운 아키텍처적 고민이 파생됩니다. 만약 트래픽이 폭주하여 결제 서비스 인스턴스가 5대로 스케일 아웃(Scale-out) 되었다고 가정해 보겠습니다. 클라이언트 서비스가 5대의 가용한 결제 서버 IP 목록을 확보했다면, 과연 이 5대의 서버 중 '어떤 인스턴스'로 API 요청을 보내야 특정 서버가 과부하로 쓰러지는 것을 막고 시스템 전체의 부하를 가장 골고루 분산시킬 수 있을까요?

다음 포스팅에서는 이 질문에 대한 해답이자, 분산된 여러 인스턴스에 트래픽을 지능적으로 분배하는 MSA의 필수 기술인 '로드 밸런싱(Load Balancing)'에 대해 다루어 보겠습니다.

 

반응형