Service Discovery 란?
- MSA 에서 서비스간 원격 호출 시 각 서비스의 IP/Port 등의 정보를 알아야 한다.
- Cloud 환경에서 오토스케일등에 의해 동적 생성되거나 컨테이너 기반 배포로 인해 서비스의 IP 가 동적으로 변경된다.
- Microservice 가 다른 서비스를 호출할 때 해당 서비스의 위치 정보를 알아낼 수 있는 기능이 필요하다.
- 이것을 바로 서비스 디스커버리 라고 한다.
Client side discovery
- A Service 의 인스턴스들이 생성될 때 Service registry 에 등록한다.
- Client 는 Service registry 에 Service A 의 주소를 물어보고 등록된 주소를 받아 호출한다.
- 비교적 간단하다. (장)
- Client 가 사용 가능한 서비스 인서튼스에 대해 알수 있기 때문에 각 서비스별 로드밸런싱 방법을 선택할 수 있다. (장)
- Client 와 Service registry 간 dependency (단)
- Client (language, framework이 다를 수 있음)에서 service discovery 로직 (regster 나 discovery)를 구현해야 함 (단)
- ex) Netflix-Eureka
Server side discovery
- A Service 의 인스턴스들이 생성될 때 Service registry 에 등록한다.
- Client 는 Proxy (로드밸런서) 를 호출 한다. (API Gateway 에서 이 역할을 할 수 있다)
- Proxy 가 Service registry 로 부터 A 서비스 위치를 확인하고 라우팅 한다.
- Discovery 기능이 client 로 부터 분리되어 있어 의존성이 낮다. (장)
- Client (language, framework이 다를 수 있음)에서 service discovery 로직 (regster 나 discovery)를 구현 필요 없다 (장)
- Kubernetes Cluster, AWS Elastic Load Balancer 등의 환경에서는 server side discovery 를 무료 제공한다. (장)
- 고가용성 로드밸런서가 배포 환경에 제공되어야 한다. (단)
- ex) AWS ELB(Elastic Load Banancer), Kubernetes Cluster
Service Registry
- Service Discovery 의 Key-Point 로 각 서비스 인스턴스의 network location 정보를 포함하는 DB 와 같다.
- 높은 가용성이 보장되어야 하며 최신 상태 정보를 유지해야 한다.
- 이를 위해 Service discovery 에 전문화된 솔루션인 Eureka, Consul, Zookepper, etcd 등을 이용하는 것이 좋다.
Eureka
- Microservice 들의 정보를 registry 에 등록하여 관리할 수 있도록 한다.
- Microservice 인스턴스의 증설, 삭제 등을 동적으로 탐색하며 Ribbon 을 이용해 추가적인 로드밸런싱까지 사용할 수 있다.
- 로드밸런싱과 장애 복구가 가능한 서비스 환경을 구성할때 client 에게 가용한 서비스 인스턴스의 network location 정보를 동적으로 제공할 수 있다.
Eureka 구성
- Eureka Server: Service Registry 서버
- 등록 정보는 service id 와 url 을 포함한다.
- microservice 가 시작되면 Eurka server 에 접근해서 service id, url 등의 정보를 자동으로 등록하고 30초 모다 heartbeat ping 을 날린다.
- Eureka Client: eurka 에 다른 서비스 위치를 조회하는 서비스
- Eureka Service: Eureka 에 등록을 요청한 서비스
- Eureka Instance: Eureka 에 등록된 조회 가능한 Eureka Service
Eureka Server
Service registry 역할을 하는 eureka server 를 개발해 보자.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Spring initialize project 구성 시 eureka server 를 check 하거나 dependency 에 직접 추가
server:
port: 8881
spring:
application:
name: yhkim-eureka-server
# 자기 자신을 자동 등록 하지 않도록 false 설정
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
renewal-percent-threshold: 0.85
.yaml 에 필요한 정보를 설정한다.
@SpringBootApplication @EnableEurekaServer
public class EurekaServerTestApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerTestApplication.class, args);
}
}
@EnableEurekaServer 를 추가해주면 끝
run 해서 설정한 port 로 접속해 보면 정상적으로 구동된것을 볼 수 있다.
Eureka Client
service registry 에 등록한 client app 에 eureka 를 적용한다고 생각하면 된다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
필요한 dependency 를 추가해 주고
spring:
application:
name: yhkim-eureka-client-a
server:
port: 0
eureka:
client:
service-url:
defaultZone: http://localhost:8881/eureka/
instance:
instance-id: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
.yaml 에 필요한 정보를 설정해 준다.
application.name 은 eurka server 에서 식별되는 값으로 해당 서비스의 이름을 적어주면 된다.
service-url 의 defaultZone 에 위에서 설정한 eureka server url 을 적어주고
server.port 는 이 서비스의 instance 를 여러개 띄울때 random 하게 띄우기 위해 0 으로 설정했다.
여러개의 instance 가 하나의 application 으로 instance id 만 unique 하게 갖도록 하기 위해 instance-id 를 위와 같이 설정해 주었다.
@SpringBootApplication
@EnableEurekaClient
public class EurekaClientTest1Application {
public static void main(String[] args) {
SpringApplication.run(EurekaClientTest1Application.class, args);
}
}
@EnableEurekaServer 처럼 @EnableEurekaClient 만 적용하면 쉽게 적용할 수 있다.
@RestController
public class TestController {
@Value("${eureka.instance.instance-id}")
String instanceId;
@GetMapping("/a/hello")
public ResponseEntity<String> testC() {
return ResponseEntity.ok("Hello Younghoi Kim, it's eureka - " + instanceId);
}
}
test 를 위해 controller 를 하나 만들어 보자.
Run 해보면
eureka server 에 registering service... 하고 정상적으로 (204 No-Content) 등록된 것을 볼 수 있다.
3개의 instance 를 run 하면 Eureka server 에서 3개의 instance 가 모두 정상 등록된 것을 확인할 수 있다.
이제 위 서비스(yhkim-eureka-client-a)를 호출하는 다른 Micoreservice (yhkim-eureka-client-b)를 추가해 보자.
yhkim-eureka-client-a 와 동일하게 dependency 추가하고 @EnableEurekaClient 하고 아래와 같이 controller 를 만들어서 a 서비스를 호출해 보자.
@RestController @RequiredArgsConstructor @Slf4j
public class TestController {
final RestTemplate restTemplate;
final DiscoveryClient discoveryClient;
@GetMapping("/b/hello")
public ResponseEntity<String> hello() {
String baseUrl = "";
List<ServiceInstance> list = discoveryClient.getInstances("YHKIM-EUREKA-CLIENT-A");
for (ServiceInstance instance : list) {
log.info("{}", instance.toString());
}
baseUrl = list.get(0).getUri().toString();
return ResponseEntity.ok(restTemplate.getForObject(baseUrl + "/a/hello", String.class));
}
}
eureka 에 등록되어 있는 name 으로 a 서비스를 찾아서 그중 첫번째 instance 로 호출하도록 해 두었다.
a 서비스의 network location 정보를 알 수 없는 상태에서 오토스케일링, 배포 등의 작업이 진행되더라도 b 서비스는 eureka server 를 통해 a 서비스의 위치 정보를 받아 호출이 가능해 졌다.
소스 코드를 보면 (baseUrl = list.get(0).getUri());
instance 가 여러개가 있는데 이 중 첫번째 instance 를 가져와 호출하도록 한 상태다.
각 instance 의 상태를 고려하고나 random 하게 또는 로드밸런싱의 기본적인 알고리즘인 라운드 로빈 방식등을 이용해서
로드밸런싱 하려면 어떻게 해야 할까?
이건 다음 시간에 Ribbon, Spring Cloud Loadbalancer 를 이용해 확인해 본다.
'IT > Spring Cloud' 카테고리의 다른 글
Spring Cloud 시리즈 5 - Loadbalancer (feat. Ribbon) (0) | 2023.06.01 |
---|---|
Spring Cloud 시리즈 3 - Resilience4j #2 (0) | 2023.05.25 |
Spring Cloud 시리즈 3 - Resilience4j #1 (0) | 2023.05.23 |
Spring Cloud 시리즈 3 - Circuit Breaker (Hystrix) (0) | 2023.05.22 |
Error creating bean with name 'configurationPropertiesBeans' defined in org.springframework.cloud.autoconfigure.... (0) | 2023.05.22 |