[MSA] 서비스 호출하기
준비물
Product Service
- port : 8081
- api : GET /products/{productId}
Display Service
- port : 8080
- api : GET /display/{productId}
Spring Boot
- 2.3.8
- 각 서비스별로 spring.application.name 작성 해두기
Spring boot에서 서비스 호출하기
클라이언트는 Api gateway를 통해 Display Service만 접근 하는 시나리오이며, Display Service는 내부적으로 Product Service를 호출한다.
1. RestTemplate
RestTemplate에 서비스의 주소를 명시하여 호출하는 방법
@Service
public class ProductService {
private static final String url = "http://localhost:8081/products/";
private final RestTemplate restTemplate;
public ProductService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getProductInfo(String productId) {
return restTemplate.getForObject(url + productId, String.class);
}
}
2. Hystrix으로 CircuitBreak 적용하기
- Hystrix Dependency 추가
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix' }
- @EnableCircuitBreaker 추가
@EnableCircuitBreaker public class DisplayApplication {
- Fallback method 정의
@Service public class ProductService { private static final String url = "http://localhost:8081/products/"; private final RestTemplate restTemplate; public ProductService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @HystrixCommand(fallbackMethod = "getProductFallback") public String getProductInfo(String productId) { return restTemplate.getForObject(url + productId, String.class); } public String getProductFallback(String productId, Throwable throwable) { return "[ sold out ]"; } }
FallbackMethod에 Throwable 객체를 함께 넘겨 줄 수 있다. (생략 가능)
Timeout 적용
application.yml에 timeout 적용하기
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
@HystrixCommand에 command key를 지정해두지 않으면 default가 기본 설정이 된다.
CircuitBreaker 적용
application.yml에 Circuit breaker 를 위한 설정
hystrix:
command:
default:
...
circuitBreaker:
requestVolumeThreshold: 1
errorThresholdPercentage: 50
3. Ribbon으로 LoadBalance 적용하기
- Ribbon Dependency 추가
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-ribbon' }
- application.yml에 서비스명과 서버 주소를 추가
product: ribbon: listOfServers: localhost:8081, localhost:8082 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1
MaxAutoRetries: 첫 시도 실패시 같은 서버로 재시도 하는 수
MaxAutoRetriesNextServer : 첫 시도 실패시 다음 서버로 재시도 하는 수
- Product 서비스 호출 url 변경
@Service public class ProductService { private static final String url = "http://product/products/"; ...
- RestTemplate Bean에 @LoadBalanced어노테이션 추가
@Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
4. Eureka 추가하기
4.1. Eureka 서버 추가
- 새 Spring Boot 앱 추가 후 Eureka Server 의존성 추가
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' }
- @EnableEurekaServer 어노테이션 추가
@SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { ...
- application.yml에 Eureka 설정
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
server:
response-cache-update-interval-ms: 1000 # Default 30,000ms
enableSelfPreservation: false # Just for demo
client:
register-with-eureka: false # Only for local stand-alone development
fetch-registry: false # Only for local stand-alone development
service-url:
defaultZone: http://localhost:8761/eureka # Default Value. Just for demo
instance:
prefer-ip-address: true # Use ip address instead of hostname from OS when reporting myself to eureka server
4.2. Product, Display서비스에 Eureka Client 추가
- Eureka Client 의존성 추가
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' }
- application.yml에 Eureka 설정 추가
eureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://127.0.0.1:8761/eureka
- @EnableEurekaClient어노테이션 추가
@EnableEurekaClient
@SpringBootApplication
public class ProductApplication {
...
4.3. Display 서비스에 listOfSevers 제거
product:
ribbon:
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1
5. Spring Cloud Feign 사용하기
- Spring Cloud Feign 의존성 추가
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' }
- @EnableFeignClients 어노테이션 추가
@EnableFeignClients public class DisplayApplication {
- FeignClient 인터페이스 생성
@FeignClient(name = "product", url = "http://localhost:8081/") public interface FeignProductService { @RequestMapping(path = "/products/{productId}") String getProductInfo(@PathVariable("productId") String productId); }
Eureka와 Ribbon을 사용 할 경우 url을 제거할 수 있다.
- Bean 주입 후 사용하기
private final FeignProductService feignProductService; ... private String getProductInfo(String productId) { return feignProductService.getProductInfo(productId); }
5.1. Feign Client에 Hystrix 적용하기
- application.yml에 Feign Client에서 Hystrix설정을 켜기
feign: hystrix: enabled: true
- FeignClient인터페이스를 구현한 클래스에 Fallback 메서드를 정의
@Component public class FeignProductServiceFallbackImpl implements FeignProductService { @Override public String getProductInfo(String productId) { return "sold out"; } }
- FeinClient인터페이스에 Fallback 메서드 설정
@FeignClient(name = "product", fallback = FeignProductServiceFallbackImpl.class) public interface FeignProductService { @RequestMapping(path = "/products/{productId}") String getProductInfo(@PathVariable("productId") String productId); }
- application.yml에 Hystrix 값 설정하기
hystrix:
command:
FeignProductService#getProductInfo(String):
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
circuitBreaker:
requestVolumeThreshold: 1
errorThresholdPercentage: 50
6. Gateway 추가하기
6.1. Zuul 추가
- 새 Spring Boot 앱 추가 후 Eureka Client, Zuul 의존성 추가
dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' }
- @EnableZuulProxy, @EnableDiscoveryClient 어노테이션 추가
@EnableZuulProxy @EnableDiscoveryClient @SpringBootApplication public class ZuulApplication { ...
- application.yml에 Zuul 설정
spring:
application:
name: zuul
server:
port: 9000
zuul:
routes:
product:
path: /products/**
serviceId: product
stripPrefix: false
display:
path: /displays/**
serviceId: display
stripPrefix: false
eureka:
instance:
non-secure-port: ${server.port}
prefer-ip-address: true
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
6.2. Gateway에 Ribbon 로드밸런싱 추가
- application.yml에 ribbon 설정
product:
ribbon:
MaxAutoRetriesNextServer: 1
ReadTimeout: 3000
ConnectTimeout: 1000
MaxTotalConnections: 300
MaxConnectionsPerHost: 100
display:
ribbon:
MaxAutoRetriesNextServer: 1
ReadTimeout: 3000
ConnectTimeout: 1000
MaxTotalConnections: 300
MaxConnectionsPerHost: 100