Server-side discovery

Server-side Discovery Server-side Discovery는 클라이언트가 서비스의 위치를 직접 찾지 않고, 중간에 위치한 로드 밸런서나 프록시 서버가 서비스 위치를 찾아 요청을 라우팅하는 방식이다. Server-side Discovery는 클라이언트를 단순화하고 중앙 집중식 관리를 가능하게 하는 장점이 있지만, 추가 인프라와 관리가 필요한 단점도 있다. 프로젝트의 요구사항과 팀의 역량을 고려하여 적절히 선택해야 한다. 작동 원리 서비스 등록: 각 서비스 인스턴스는 시작 시 자신의 정보를 서비스 레지스트리에 등록한다. 클라이언트 요청: 클라이언트는 서비스의 실제 위치를 모르고, 로드 밸런서에 요청을 보낸다. 서비스 조회: 로드 밸런서는 서비스 레지스트리에서 해당 서비스의 가용한 인스턴스 정보를 조회한다. 요청 라우팅: 로드 밸런서는 적절한 서비스 인스턴스를 선택하여 요청을 전달한다. 응답 반환: 서비스의 응답은 로드 밸런서를 통해 클라이언트에게 전달된다. 장점 클라이언트 단순화: 클라이언트는 서비스 디스커버리 로직을 구현할 필요가 없어 단순해진다. 언어 중립성: 클라이언트 측 구현이 필요 없어 다양한 프로그래밍 언어로 개발된 서비스들을 쉽게 통합할 수 있다. 보안 강화: 로드 밸런서 수준에서 추가적인 보안 계층을 구현할 수 있다. 중앙 집중식 관리: 서비스 디스커버리와 로드 밸런싱을 중앙에서 관리할 수 있다. 단점 추가 인프라 필요: 로드 밸런서나 프록시 서버와 같은 추가 인프라가 필요하다. 단일 실패 지점: 로드 밸런서가 단일 실패 지점이 될 수 있어 고가용성 설계가 중요하다. 복잡성 증가: 전체 시스템의 복잡성이 증가할 수 있다. 구현 예시 AWS Elastic Load Balancer (ELB): 클라이언트는 ELB의 DNS 이름을 통해 요청을 보내며, ELB는 등록된 EC2 인스턴스나 ECS 컨테이너 사이에서 부하를 분산한다. Kubernetes의 kube-proxy: Kubernetes에서는 각 노드에서 실행되는 kube-proxy가 서비스 디스커버리와 로드 밸런싱을 담당하며, 클러스터 내의 서비스 요청을 적절한 파드(Pod)로 전달한다. Node.js를 사용한 Server-side Discovery 구현 예시 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 // 서버 사이드 디스커버리 라우터 구현 class ServiceRouter { constructor(options = {}) { this.registryUrl = options.registryUrl || 'http://service-registry:8500'; this.serviceCache = new Map(); this.cacheTimeout = options.cacheTimeout || 30000; // 30초 this.loadBalancer = new LoadBalancer(); } async handleRequest(req, res) { const serviceName = this.extractServiceName(req); try { // 서비스 인스턴스 찾기 const serviceInstance = await this.findServiceInstance(serviceName); // 요청 전달 const response = await this.forwardRequest(req, serviceInstance); // 응답 전달 this.sendResponse(res, response); } catch (error) { this.handleError(res, error); } } async findServiceInstance(serviceName) { // 캐시된 서비스 확인 const cachedInstances = this.getCachedInstances(serviceName); if (cachedInstances && cachedInstances.length > 0) { return this.loadBalancer.selectInstance(cachedInstances); } // 서비스 레지스트리 조회 const instances = await this.queryRegistry(serviceName); this.updateCache(serviceName, instances); return this.loadBalancer.selectInstance(instances); } async forwardRequest(req, serviceInstance) { const targetUrl = this.buildTargetUrl(serviceInstance, req.path); return await fetch(targetUrl, { method: req.method, headers: req.headers, body: req.body, timeout: 5000 }); } } 참고 및 출처

November 14, 2024 · 2 min · Me