[Spring Cloud로 개발하는 마이크로서비스 애플리케이션]-MSA간 통신 (Rest Template)

Sungjin·2021년 7월 5일
1
post-thumbnail

MSA간 통신이 필요 이유?

물리적으로 분산된 시스템 서비스간의 통신 필수
ex) user service와 order service가 분산되어있는 경우(DB도 각각의 DB를 가짐) Client에게 주문 내역을 보여주기 위해서는 서로간의 통신이 필요!

Communication Type

  • 동기 방식
    Client의 요청이 들어오면 작업이 끝날 때 까지 다른 작업은 불가
  • 비동기 방식
    AMQP라는 프로토콜을 이용하여 각 MSA간 비동기 방식으로 변경된 사항을 전달 가능
  • 활용 방안
    user service가 order service를 호출할 때 order service가 Load Balancer의 이유로 두 개 이상이 등록되어 있다고 가정!
    1. 가장 기본적인 방법으로 Round Robin알고리즘을 사용해 Eureka Server에서 order service의 위치를 알아 내 직접적으로 호출하는 방법
    2. Rest Template이라는 API 사용
      • 기존의 Java로 만들어진 어플리케이션 간 Http를 이용
      • Rest Template이라는 객체를 생성하여 통신하고자 하는 객체에에 요청을 보내가 반환 값을 받아오는 형식. 즉, user service의 대리자 처럼 사용
    3. Feign Client
      다음에 알아봅시다~

Test

user service에 Rest Template을 사용 해 봅시다 :)

  • 전제 조건
    1. user service와 order service는 Eureka Server에 등록되어 있어야 함.
    2. Load Balancer를 위해 Gateway Server에 order service,user service가 Routing 정보로 포함되어 있어야 함.
    3. Controller, Service, Repository는 이미 개발 되었다는 전제에 Rest Template만을 추가 해 보도록 하겠습니다.
  • CODE

1. Bean으로 등록

@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(UserServiceApplication.class, args);
	}


	@Bean
	public RestTemplate getRestTemplate(){
		return new RestTemplate();
	}
}

2. user service에 service에 Rest Template 추가.( 빈으로 등록된 Rest Template을 주입 받는 과정 필요 - 이 과정은 생략)

order-service

@GetMapping("/{userId}/orders")
public ResponseEntity<List<ResponseOrder>> 
getUsers(@PathVariable("userId")String userId){
    List<OrderDto> orders = orderService.getOrdersByUserId(userId);
    List<ResponseOrder> responseOrders=new ArrayList<>();

    List<ResponseOrder> collect = orders.stream()
                .map(o -> new ResponseOrder(o.getProductId(), 
                o.getUnitPrice(), 
                o.getTotalPrice(), 
                o.getStock(), 
                o.getCreatedAt(), 
                o.getOrderId()))
                .collect(Collectors.toList());

    return ResponseEntity.status(HttpStatus.OK).body(collect);
}

user-service

@Override
public UserDto getUserByUserId(String userId) {
    UserEntity userEntity=userRepository.findByUserId(userId);
    if (userEntity==null)
        throw new UsernameNotFoundException("User not found");
    UserDto userDto=new ModelMapper().map(userEntity,UserDto.class);

//  Rest Template으로 order-service에다 요청을 보내는 과정
    String orderUrl="http://127.0.0.1:8000/order-service/%s/orders"; 
    ResponseEntity<List<ResponseOrder>> 
    orderListResponse = restTemplate.exchange(orderUrl, 
    					HttpMethod.GET, 
    					null,
                        new ParameterizedTypeReference<List<ResponseOrder>>(){
                });
           
    List<ResponseOrder> orderList = orderListResponse.getBody();
    userDto.setOrders(orderList);
    return userDto;
}

Rest Template을 활용하여 user-service에서 order-service에 요청을 보내고 응답을 받는 모습을 보여주고 있음.

3. Re Factoring
2번에서의 user-service의 코드를 보면 코드에서 직접 URL에 요청을 보내고 있는 모습을 볼 수 있습니다. 만약 요청하고자 하는 URL의 IP가 변경되거나 Port가 변경되는 등 변경 사항이 생기게 되면 코드를 다시 고쳐야하는 번거로운 작업이 필요할 수 있습니다. 따라서, Configuration 정보에 요청하고자 하는 service에 URL을 저장해놓고 사용하는 것이 바람직 합니다. 이를 위해서는 Environment 객체를 주입 받아서 사용 하여야 합니다. (주입하는 과정은 생략)

Configuration 파일에
order_service:
url: http://127.0.0.1:8000/order-service/%s/orders
이와 같이 명시 해 놓으면 됩니다!

user-service

@Override
public UserDto getUserByUserId(String userId) {
    UserEntity userEntity=userRepository.findByUserId(userId);
    if (userEntity==null)
        throw new UsernameNotFoundException("User not found");
    UserDto userDto=new ModelMapper().map(userEntity,UserDto.class);

//  Rest Template으로 order-service에다 요청을 보내는 과정
    //String orderUrl="http://127.0.0.1:8000/order-service/%s/orders"; 
    
    String orderUrl=String.format(env.getProperty("order_service.url")
   				 ,userId);
    
    ResponseEntity<List<ResponseOrder>> 
    orderListResponse = restTemplate.exchange(orderUrl, 
    					HttpMethod.GET, 
    					null,
                        new ParameterizedTypeReference<List<ResponseOrder>>(){
                });
           
    List<ResponseOrder> orderList = orderListResponse.getBody();
    userDto.setOrders(orderList);
    return userDto;
}
  • 실행 결과

    잘 동작하는 것을 볼 수 있습니다!

이상으로 포스팅을 마치겠습니다. 다음 번엔 Feign Client 및 예외 처리에 대하여 알아보아요~ :)

이 글은 인프런 이도원님의 'Spring Cloud로 개발하는 마이크로서비스 애플리케이션'을 수강하고 작성합니다.
출처:https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4/dashboard

profile
WEB STUDY & etc.. HELLO!

0개의 댓글