서비스 디스커버리
- 서비스의 물리적 위치를 추상화
- 서비스 클라이언트가 인스턴스의 물리적 위치를 몰라도 되어, 서비스 인스턴스의 수평 확장 및 축소가 자유로움
- 비정상 인스턴스를 가용 서비스 목록에서 제거하여 회복성 높임
- 예 : 넷플릭스 유레카
주요 특징
1. 고가용성
- 서비스 목록을 여러 노드가 공유하는 클러스터링 환경 지원.
2. 피어 투 피어
- 각 노드는 서비스 인스턴스 상태를 공유함.
3. 부하 분산
- 클라이언트 요청을 동적으로 부하 분산하여 모든 서비스 인스턴스에 분해함.
4. 회복성
- 클라이언트는 서비스 정보를 로컬에 캐시하여 서비스 디스커버리가 가용하지 않을 때에도 서비스를 계속 찾을 수 있음.
5. 장애 내성
- 서비스 인스턴스의 비정상을 탐지하고 가용 서비스 목록에서 인스턴스를 제거함.
서비스 디스커버리 주요 과정
- 서비스 인스턴스가 시작하면 서비스 디스커버리 인스턴스가 접근할 수 있는 자신의 물리적 위치와 경로, 포트를 등록
- 서비스의 각 인스턴스에는 고유한 IP주소와 포트가 있지만 동일한 서비스 ID로 등록. 이때 서비스 ID는 동일한 서비스 인스턴스 그룹을 고유하게 식별하는 키
- 서비스는 일반적으로 1개의 서비스 디스커버리 인스턴스(노드)에만 등록. 그리고 다른 노드에 전파함.
- 각 서비스 인스턴스는 자기 상태를 서비스 디스커버리에 푸시하거나 서비스 디스커버리가 인스턴스 상태를 추출.
클라이언트 측 부하 분산
- 모든 서비스 인스턴스 정보를 서비스 디스커버리에서 가져와 서비스 소비자 기기에 로컬 캐시함.
- 클라이언트가 서비스를 호출하려 할 때 마다 서비스 소비자는 캐시에서 위치 정보 검색.
- 클라이언트는 주기적으로 서비스 디스커버리 서비스에 접속해 서비스 인스턴스 캐시를 새로고침함.
- 예 : 넷플릭스 리본 라이브러리
서비스 디스커버리 및 클라이언트 측 부하 분산
- 스프링 클라우드와 넷플릭스의 유레카 서비스 디스커버리 엔진을 사용해 서비스 디스커버리 패턴을 구현하고, 클라이언트 측 부하 분산을 위해 스프링 클라우드와 넷플릭스의 리본 라이브러리를 사용
주요 과정
- 서비스 부트스트래핑 시점에 라이선싱 및 조직 서비스는 자신을 유레카 서비스에 등록. 이 등록 과정에서 서비스 ID와 함께 각 서비스 인스턴스의 물리적 위치, 포트 번호를 유레카에 알려줌.
- 라이선싱 서비스가 조직 서비스를 호출할 때 넷플릭스 리본 라이브러리를 사용해 클라이언트 측 부하 분산 기능을 수행. 리본 라이브러리는 유레카 서비스에서 서비스의 위치 정보를 조회하고 로컬에 캐싱.
- 주기적으로 넷플릭스 리본 라이브러리는 유레카 서비스를 핑해서 로컬 캐시의 서비스 위치를 새로고침.
유레카 서비스 디스커버리 구현
새로운 스프링 부트 프로젝트 생성 (eurekasvr)
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<groupId>com.hmg</groupId>
<artifactId>eurekasvr</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eurekasvr</name>
<description>eureka service discovery</description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
...
</project>
유레카 서비스를 독립 실행 모드로 설정하는 데 필요한 구성(예를 들어 클러스터에 다른 노드가 없는 구성)
- application.yml
# 유레카 서버가 수신 대기할 포트
server:
port: 8761
eureka:
client:
# 유레카 서비스에 (자신을) 등록하지 않는다.
registerWithEureka: false
# 레지스트리 정보를 로컬에 캐싱하지 않는다.
fetchRegistry: false
server:
# 서버가 요청을 받기 전 대기할 초기 시간 (로컬에서만 사용)
#waitTimeInMsWhenSyncEmpty: 5
# 컨테이너 실행시 read-timeout 에러 떠서 추가
peer-node-read-timeout-ms: 10000
serviceUrl:
defaultZone: http://localhost:8761
유레카 서비스 애플리케이션 부트스트랩 클래스
- Application.java
package com.hmg.eurekasvr;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // 스프링 서비스에서 유레카 서버 활성화
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
스프링 유레카에 서비스 등록 (서비스 측 구현)
조직(라이선싱) 서비스에 스프링 유레카 의존성 추가
- pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-neflix-eureka-client</artifactId> -- 유레카에 서비스를 등록할 수 있도록 유레카 라이브러리 포함
</dependency>
스프링 부트에 조직서비스를 유레카에 등록하도록 지정
- bootstrap.yml
spring:
application:
name: organizationservice -- 유레카에 등록할 서비스의 논리 이름
profiles:
active: default
cloud:
config:
enabled: true
- application.yml
eureka:
instance:
# 서비스 이름 대신 서비스 IP 주소 등록
preferIpAddress: true
client:
# 유레카에 서비스 등록
registerWithEureka: true
# 유레카 서비스 위치
fetchRegistry: true
# 레지스트리 사본을 로컬로 가져오기
serviceUrl:
defaultZone: http://localhost:8761/eureka/
유레카 서비스 디스커버리에 서비스가 등록되면 유레카 REST API를 호출해 레지스트리 내용 확인이 가능
GET http://<eureka service>:8761/eureka/apps/<APPID>
- 예시 : GET http://localhost:8761/eureka/apps/organizationservice
참고
서비스를 유레카에 등록하면 서비스가 가용하다고 확인될 떄 까지 유레카는 30초간 연속 세 번의 상태 정보를 확인하며 대기함(warm-up 시간). 따라서 서비스를 호출하기 전에 30초 정도 기다리자.
서비스 디스커버리를 사용해 서비스 검색
서비스 소비자가 리본과 상호 작용할 수 있는 스프링/넷플릭스 클라이언트 라이브러리가 세가지 존재
- 스프링 디스커버리 클라이언트
- RestTemplate이 활성화된 스프링 디스커버리 클라이언트
- 넷플릭스 Feign 클라이언트
그 중 추상화 수준이 가장 높은 넷플릭스 Feign 클라이언트를 통해 서비스 검색 구현
(licensing-service -> organization-service 서비스 검색)
dependency 추가
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Feign 클라이언트 활성화
- Application.java
@SpringBootApplication
@EnableFeignClients // FeignClient를 사용하기 위해 애너테이션 추가
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
조직 서비스 엔드포인트를 호출할 Feign 클라이언트 인터페이스 정의
- 인터페이스만 생성해 주면 스프링 클라우드 프레임워크는 대상 REST 서비스를 호출하는 데 사용되는 프록시 클래스를 동적으로 생성한다.
- @FeignClient 애너테이션으로 organizationservice의 물리적 위치를 리본에서 받아와 RestTemplate 호출해준다.
- @Autowired로 클래스를 주입받아 getOrganization() 메서드 사용 가능
- OrganizationFeignClient.java
@FeignClient("organizationservice") // FeignClient 애너테이션으로 조직 서비스를 Feign에 확인
public interface OrganizationFeignClient {
@RequestMapping(
method= RequestMethod.GET,
value="/v1/organizations/{organizationId}", // 조직 정보 조회
consumes="application/json") // @RequestMapping 애너테이션으로 엔드포인트 경로와 액션 정의
Organization getOrganization(@PathVariable("organizationId") String organizationId); // @PathVariable 애너테이션으로 엔드포인트에 전달하는 매개변수 정의
}
licensing-service 에서 oragnization-service 호출해보기
상세 컨트롤러 및 서비스 로직은 https://github.com/hmg0616/msainaction-repo 에 licensing-service 모듈에서 확인
GET http://licensing-service/v1/organizations/{organizationId}/licenses/{licenseId}
GET http://localhost:8080/v1/organizations/e254f8c-c442-4ebe-a82a-e2fc1d1ff78a/licenses/f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a
'MSA > Spring Microservice In Action' 카테고리의 다른 글
5. 나쁜 상황에 대비한 스프링 클라우드와 넷플릭스 히스트릭스의 클라이언트 회복성 패턴 (0) | 2022.02.19 |
---|---|
부록. Dockerfile과 Docker-compose를 이용한 프로젝트 빌드 및 실행 (0) | 2022.01.20 |
3. 스프링 클라우드 컨피그 서버로 구성 관리 (0) | 2022.01.02 |
2. 스프링 부트 마이크로 서비스 구축 (0) | 2021.12.28 |
1. Spring Microservice 개요 (0) | 2021.12.28 |
댓글