마이크로서비스에서 Service Discovery란 무엇인가
October 21, 2022
서비스 디스커버리란 무엇인가? 왜 필요한가?
인터넷 초기에는 사람들이 온라인 서비스에 접근하기 위해 긴 IP 주소 문자열을 입력해야 했습니다. IP 주소는 길지 않았지만, 의미 없는 숫자 문자열이기 때문에 특정 서비스의 주소를 기억하는 것은 어려운 일이었고, 이로 인해 도메인 이름 시스템이 발명되었습니다. 각 온라인 서비스는 도메인 이름 제공업체에 도메인 이름을 등록한 후 DNS(Domain Name System)를 통해 도메인 이름과 특정 IP를 연결했습니다. 이렇게 하면 사람들은 기억하기 쉬운 도메인 이름을 입력하고 특정 IP의 온라인 서비스에 접근할 수 있었는데, 이것이 서비스 디스커버리의 초기 형태였습니다.
회사 내부의 서비스 수가 일정 규모에 도달하면(예: 마이크로서비스로 분할), IP를 기억하기 어려운 문제가 발생하며, 이를 해결하기 위해 서비스 디스커버리 시스템이 필요합니다. 회사 내부의 서비스는 이 시스템에 등록하고, 이를 접근하려는 다른 서비스는 시스템에서 해당 IP 주소를 조회하여 복잡하고 변동 가능한 IP 주소를 "기억"할 필요가 없게 됩니다.
IP 주소 변경은 방문자를 혼란스럽게 할 수 있습니다.
DNS를 서비스 디스커버리 메커니즘으로 도입함으로써 IP 변경을 유연하게 처리할 수 있습니다.
일반적인 서비스 디스커버리 시스템 소개
서비스 디스커버리 시스템으로서 최소한 네 가지 기능을 충족해야 합니다:
- 등록을 위한 API
- 조회를 위한 API
- 고가용성: 서비스 디스커버리 시스템은 전체 시스템의 핵심이므로 마비되거나 충돌해서는 안 됩니다
- 생태계: 프로그래머들은 게으르기 때문에 API와 쉽게 상호작용할 수 있는 라이브러리를 선호합니다
시장에서 주류 오픈소스 서비스 디스커버리 시스템 몇 가지를 살펴보겠습니다:
Consul
Consul은 Hashicorp라는 선도적인 오픈소스 회사에서 개발한 서비스 디스커버리 시스템입니다. 2014년 4월 17일 첫 버전을 출시한 오랜 역사를 가진 소프트웨어로, Consul은 가장 풍부한 생태계를 가지고 있으며, 심지어 Haskell의 SDK를 개발하는 제3자 개발자도 있습니다. Consul의 SDK는 대부분 HTTP API에 대한 래퍼일 뿐이므로 개발 작업이 많지 않습니다.
Consul은 HTTP API를 통해 서비스 등록 및 조회를 지원합니다. 조회 시 데이터를 실시간으로 푸시하기 위해 HTTP 롱 폴링을 지원하여 폴링을 피할 수 있습니다. 또한 Consul은 DNS를 통해 해당 서비스의 인스턴스를 조회할 수 있습니다.
Consul의 배포는 흥미로운데, 각 Consul 인스턴스를 에이전트라고 부르며, 클라이언트 또는 서버가 될 수 있습니다. 클라이언트 측에서는 Consul이 클라이언트 측 상태를 유지하고, 서버 측에서는 일관성 알고리즘 Raft를 통해 분산 배포를 지원하여 고가용성을 달성합니다.
Eureka
Eureka는 Netflix가 오픈소스로 공개한 프로젝트로, 상당히 오래되었습니다(2012년으로 거슬러 올라가는 커밋 흔적이 있습니다). 그러나 이 프로젝트는 1년 동안 유지보수가 되지 않았습니다. 많은 사용자들이 아래에서 언급할 Nacos로 이전했습니다.
Eureka는 HTTP API와 Java SDK를 통해 상호작용을 지원합니다. Eureka의 많은 사용자들은 실제로 Spring Cloud와 같은 Java 생태계 프로젝트를 통해 유입되었습니다. Eureka의 고가용성 설계는 CAP(일관성, 가용성, 분할 내성 중 두 가지만 동시에 제공할 수 있다는 CAP 정리) 측면에서 AP로 설명할 수 있으며, 네트워크 분할 시 클라이언트가 만료된 데이터를 볼 수 있도록 하여 네트워크 문제로 인한 2차 재난을 방지합니다.
Nacos
Nacos는 Alibaba가 개발한 서비스 디스커버리 시스템으로, 이름은 Naming과 Configuration Service의 첫 몇 글자를 합친 것입니다. 2018년 7월 20일 버전 0.1.0을 출시한 이후, Nacos는 현재 버전 2.1까지 진화했습니다.
Alibaba의 많은 오픈소스 프로젝트와 마찬가지로, Nacos는 중국의 Java 개발자들 사이에서 상당히 인기가 있으며, 그 인기는 Eureka보다 훨씬 높습니다.
Nacos는 HTTP API와 Java/Go/Python/NodeJS/C#과 같은 SDK를 통해 서비스 등록 및 조회를 지원합니다. 현재 Nacos 개발자들은 gRPC 기반의 새로운 API를 작업 중입니다. HTTP API의 경우, Nacos는 현재 서비스 목록을 폴링하는 방식만 지원합니다. 따라서 Nacos는 공식적으로 SDK 방식을 선호하며, 이는 폴링 + UDP 기반 푸시 방식으로 실시간 성능이 더 좋습니다. Nacos는 또한 gRPC 기반의 새로운 API를 작업 중이며, 이는 서버 측 푸시 기능을 도입하여 SDK에 접근할 수 없는 시스템에 큰 이점을 제공할 것입니다.
Nacos의 고가용성은 클라이언트 SDK에서 제공하는 지속성 기능과 서버 측의 Raft 및 Distro 프로토콜을 통한 일관성 덕분입니다.
일반적인 인터페이스 방식과 그 장단점
개인 프로토콜을 제외하고, 서비스 디스커버리 인터페이스 방식은 세 가지로 나눌 수 있습니다:
- HTTP 폴링
- DNS
- HTTP 롱 폴링 또는 gRPC 서버 스트리밍
HTTP 폴링은 구현이 간단하지만 실시간이 아닙니다.
DNS의 성능 오버헤드는 최소화됩니다. DNS는 DNS 캐시로 인해 실시간이 아니며, 널리 받아들여진 구현 독립적인 표준 세트라는 장점이 있습니다. 그러나 이는 양날의 검으로, 서비스 디스커버리 시스템이 DNS 응답에 추가 필드를 추가할 수 없음을 의미합니다. DNS 응답의 Additional
필드를 사용하지 않는 한, 이는 클라이언트 측에서 특별한 처리가 필요합니다.
HTTP 롱 폴링 또는 gRPC 서버 스트리밍은 세 가지 중 가장 실시간입니다. 둘 다 HTTP 기반이므로 응답을 쉽게 사용자 정의할 수 있습니다. 단점은 클라이언트 측에서 구현이 상대적으로 어렵다는 것입니다.
APISIX가 서비스 디스커버리 시스템과 인터페이스하는 방법
클라우드 네이티브 게이트웨이인 APISIX는 서비스 디스커버리 시스템에서 업스트림 노드를 가져오는 것을 지원하며, 데이터 플레인과 컨트롤 플레인 모두에서 서비스 디스커버리 시스템과 인터페이스하도록 설계되었습니다.
데이터 플레인
APISIX는 데이터 플레인에서 DNS, Eureka, Consul(KV 모드), Nacos, K8s와 통합을 지원합니다.
DNS 서비스와 인터페이스할 때, APISIX는 DNS의 SRV
또는 A/AAAA
레코드를 사용하여 서비스의 특정 업스트림 노드를 가져옵니다. 업스트림에 접근하는 요청이 있을 때, 먼저 DNS 캐시에서 가져오려고 시도합니다. 없으면 DNS 쿼리를 시작하여 해당 레코드 내의 특정 IP 주소를 가져옵니다.
다른 서비스 디스커버리 유형의 경우, 백그라운드에서 동기화됩니다. 업스트림에 접근하는 요청이 있을 때, 현재 동기화된 데이터에서 서비스 이름에 해당하는 부분을 가져옵니다. K8s와 Consul KV의 경우, HTTP 롱 폴링을 지원하므로 이 방법으로 변경된 IP 주소를 실시간으로 가져올 수 있습니다. Eureka와 Nacos의 경우 현재는 데이터를 폴링하고 있습니다.
컨트롤 플레인
APISIX는 컨트롤 플레인에서도 서비스 디스커버리를 지원합니다. apisix-seed를 작업 중이며, 이는 서비스 디스커버리 시스템에서 etcd로 데이터를 동기화하여 데이터 플레인이 etcd에서 최신 업스트림 노드를 동기화할 수 있도록 합니다.
현재 컨트롤 플레인에서 Nacos와 Zookeeper를 지원합니다. 컨트롤 플레인에서의 서비스 디스커버리 지원은 공식 SDK를 통해 구현되므로 일반 HTTP 방식에서는 사용할 수 없는 장점이 있습니다. 예를 들어, Nacos의 apisix-seed
구현에서는 UDP 기반 푸시를 지원하므로 데이터가 HTTP 폴링보다 더 실시간입니다.
APISIX가 서비스 디스커버리 시나리오를 지원하는 장점
게이트웨이에 직접 서비스 디스커버리를 통합함으로써 서비스를 온라인으로 가져오는 작업을 크게 단순화할 수 있습니다. APISIX를 서비스 디스커버리 시스템과 인터페이스하도록 구성한 후 APISIX가 나머지 작업을 수행하도록 할 수 있습니다. 예를 들어, 회사에서 Nacos를 서비스 디스커버리 시스템으로 사용하고 있다면, APISIX를 구성하여 Nacos 서비스 디스커버리를 활성화한 후 APISIX의 업스트림에 서비스 이름을 간단히 구성하면 APISIX가 해당 업스트림에 해당하는 특정 IP 노드를 자동으로 가져옵니다.
이는 게이트웨이를 마이그레이션할 때 필요한 작업량을 크게 줄일 수 있는 장점입니다. 예를 들어, Spring Cloud Gateway에서 APISIX로 마이그레이션할 때, Spring Cloud Gateway가 Eureka 또는 Nacos를 서비스 디스커버리로 사용한다면, APISIX 내에서 Eureka 또는 Nacos 지원을 활성화함으로써 새로운 시스템으로 전환할 수 있습니다.
환베이론은 이 분야에서 풍부한 경험을 가지고 있으며, Spring Cloud Gateway의 교체는 안정성, 감독, 정확성 및 효과를 더욱 개선하기 위한 것입니다.
환베이론의 원문을 인용하면:
비즈니스로서 비용은 여전히 고려해야 할 원칙입니다. 급성장 단계에서는 비즈니스 성장을 가능한 한 빨리 촉진해야 할 수도 있습니다. 그러나 현재 환경에서는 예산 내 비용이 확실히 우선순위입니다. 이 경우 효율성과 비용은 한 가지 방식으로만 보존될 수 있습니다. 따라서 제한된 비용으로 회사는 기술 발전에 대해 덜 이야기할 것입니다. 선택 과정에서 기술 직원은 선택한 기술이 팀에 얼마나 큰 영향을 미칠지, 기존 운영 및 아키텍처에 얼마나 큰 이점을 가져올지 등을 덜 고려하고, 비용 관점에서 더 많이 고려할 것입니다.
또한, APISIX는 여러 서비스 디스커버리를 동시에 구성할 수 있습니다. 역사적인 이유로 많은 회사는 여러 서비스 디스커버리 시스템을 가지고 있을 수 있습니다. 예를 들어, 제가 아는 한, 일부 회사는 기존의 Eureka 서비스 디스커버리와 새로운 Nacos 서비스 디스커버리를 모두 가지고 있습니다. APISIX는 단순히 Eureka와 Nacos를 모두 활성화하여 이 상황에 대처할 수 있습니다.
현재 APISIX에서 직접 업스트림 노드를 구성하고 있다면, 별도의 서비스 디스커버리 시스템을 배포하고 서비스 디스커버리 시스템이 특정 노드 구성을 저장하도록 하는 것을 고려할 수도 있습니다. 업스트림 노드 구성을 APISIX에서 전용 서비스 디스커버리 시스템으로 이동하는 이점은 클라이언트가 서비스 등록을 직접 수행할 수 있고, 전용 서비스 디스커버리 시스템이 종종 더 풍부한 상태 검사와 같은 추가 기능을 제공한다는 것입니다.
앞으로 APISIX Ingress Controller에서 다양한 서비스 등록 및 디스커버리 컴포넌트를 통합하여 사용자가 더 쉽게 사용할 수 있도록 지원할 예정입니다. 그때 사용자는 APISIX Ingress Controller에서 K8s 서비스의 엔드포인트를 업스트림 노드로 지정할 수 있을 뿐만 아니라 서비스 디스커버리를 통해 얻은 노드를 통합할 수 있습니다.