어떻게 마이크로서비스(MS)들은 서로 위치를 알고 호출하는 걸까?
Eureka(유레카)를 이용하여 서로 물리적 위치를 검색하여 찾기 때문이다.
서비스 디스커버리를 위해 MS들이 Spring Cloud Load Balancer(로드밸런서)와 상호 작용할 수 있는 3가지 방법을 찾아보자.
- 스프링 Discovery Client
- REST 템플릿을 사용한 스프링 Discovery Client
- 넷플릭스 Feign Client
🚀 스프링 Discovery Client
- Discovery Client와 표준 스프링 RestTemplate 클래스를 사용하여 호출
- 로드 밸런서와 그 안에 등록된 서비스에 대해 가장 낮은 수준 접근 가능
- 즉, Discovery Client를 사용하면 로드밸런서에 등록된 모든 서비스와 URL을 쿼리할 수 있음
@SpringBootApplication
@RefreshScope
@EnableDiscoveryClient // Eureka Discovery Client를 활성화
public class MicroServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MicroServiceApplication.class, args);
}
}
`@EnableDiscoveryClient`로 스프링 클라우드에서 애플리케이션이 Discovery Client와 스프링 클라우드 로드 밸런서 라이브러리를 사용할 수 있게 됨.
@Component
@RequiredArgsConstructor
public class UserDiscoveryClient {
// Discovery Client를 클래스에 주입
private final DiscoveryClient discoveryClient;
public User getUser(String userId) {
RestTemplate restTemplate = new RestTemplate();
// 유저 서비스의 모든 인스턴스 리스트를 얻음
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
if (instances.isEmpty()) return null;
// 서비스 엔드포인트를 검색해서 가져옴
String serviceUri = String.format("%s/v1/user/%s", instances.get(0).getUri().toString(), userId);
// 서비스 호출을 위해 표준 스프링 RestTemplate 클래스 사용
ResponseEntity<User> restExchange = restTemplate.exchange(serviceUri, HttpMethod.GET, null, User.class, userId);
return restExchange.getBody();
}
}
😈 단점
- Discovery Client를 직접 호출해서 모든 서비스 리스트를 얻고, 그 중 호출할 서비스 인스턴스를 개발자가 책임지고 선정
- 개발자가 서비스 호출하는 데 사용될 URL 생성
- RestTemplate을 직접 생성하여 사용
- 자동 구성이 필요하지 않고 직접적인 제어가 필요할 때 직접 생성함
- 로드밸런서 인터셉터의 영향을 피하고 특정한 설정 적용가능
🚀 로드 밸런서를 지원하는 스프링 REST 템플릿
- 향상된 스프링 RestTemplate으로 로드밸런서를 사용하는 서비스 호출
- 스프링을 통해 로드 밸런서와 상호 작용할 수 있는 일반적인 방법
@SpringBootApplication
@RefreshScope
public class MicroServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MicroServiceApplication.class, args);
}
// RestTemplate 또는 WebClient가 스프링 클라우드 서비스 디스커버리(유레카)와 통합
// 서비스 이름을 기반으로 특정 서비스에 대한 인스턴스를 선택하고 요청 가능
@LoadBalanced
@Bean
public RestTemplate getRestTemplate() {
return new RestTempalte();
}
}
- 서비스의 물리적 위치 대신 호출하려는 서비스의 유레카 서비스 ID를 사용하여 대상 URL 생성 가능
@Component
@RequiredArgsConstructor
public class UserRestTemplateClient {
private final RestTemplate restTemplate;
public User getUser(String userId) {
ResponseEntity<User> restExchange =
restTemplate.exchange("http://user-service/v1/user/{userId}", HttpMethod.GET, null, User.class, userId);
return restExchange.getBody();
}
}
- 첫 번째 방법과 다르게 Discovery Client가 없어짐
- URL에서 서버 이름은 유레카에 등록한 서비스 키의 애플리케이션 ID를 사용
- 즉, 로드 밸런서를 지원하는 RestTemplate 클래스는 전달된 URL을 파싱하고 서버 이름으로 전달된 것을 키로 사용하여 서비스의 인스턴스를 로드 밸런서에 쿼리함
- 실제 서비스 위치와 포트는 개발자에게 완전히 추상화
- RestTemplate 클래스를 사용하면 스프링 클라우드 로드 밸런서는 서비스 인스턴스에 대한 모든 요청을 라운드 로빈 방식으로 부여
🚀 Feign Client
- 넷플릭스 Feign Client 라이브러리를 사용하여 로드 밸런서를 경유하여 서비스 호출
- 자바 인터페이스를 정의하고, 스프링 클라우드 애노테이션을 추가하여 쉽게 사용
@SpringBootApplication
@RefreshScope
@EnableFeignClients // Feign Client 사용하도록 설정
public class MicroServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MicroServiceApplication.class, args);
}
}
유저 서비스의 엔드포인트를 호출할 Feign Client의 Interface 정의를 해보자.
@FeignClient("user-service") // Feign에 서비스를 알려줌
public interface UserFeignClient {
@GetMapping("/v1/user/{userId}") // 엔드포인트 경로와 액션(verb) 정의
User getUser(@PathVariable String userId); // 엔드포인트에 전달되는 매개변수 정의
}
표준 스프링 RestTemplate은 서비스 호출에 대한 HTTP 상태 코드(status code)는 ResponseEntity의 getStatus()에 반환된다. 하지만 Feign Client는 호출된 서비스에서 반환한 모든 HTTP 4xx ~ 5xx 상태코드가 FeignException에 매핑된다. 이 예외에 특정 에러 메시지에 대해 파싱할 수 있는 JSON 내용이 포함되어 있다.
Feign은 사용자가 정의한 Exception 클래스에 에러를 재매핑하는 에러 디코더(ErrorDecoder) 클래스를 작성할 수 있는 기능을 제공한다.
🚀 결론
이 중 역시 Feign Client가 가장 쉽게 작성가능하며, 추상화 되어 있고, Load Balanced 지원하기에 이것을 사용하는것이 가장 좋은 방법으로 보인다. 하지만 예외처리는 평범한 RestTemplate과는 다르니 FeignException 또는 FeignErrorDecoder, CircuitBreaker (Resilience4j) 등 클라이언트 측 회복성을 위한 다양한 방법을 숙지해야 한다.
스프링 마이크로서비스 코딩공작소 개정2판
'Spring > Spring Cloud' 카테고리의 다른 글
Spring Cloud 마이크로서비스들이 직접 Vault에서 값을 읽도록 만들어야 할까? - 보안과 유연성의 고민 (0) | 2023.10.07 |
---|---|
Spring Cloud Config Server - Vault 적용 (2) | 2023.09.23 |