• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

Mono 의 정의를 잘 모르겠습니다..

24.01.29 22:58 작성 24.01.29 23:37 수정 조회수 161

0

안녕하세요 문의 사항이 있어 글을 올립니다.

@PutMapping("/{userId}")
public Mono<User> updateUser(@PathVariable Long userId, @RequestBody UserUpdateRequestDto userRequestDto) {
   return mainService.updateUser(userId, userRequestDto);
}
public Mono<User> updateUser(Long id, UserUpdateRequestDto userUpdateRequestDto) {
   // 데이터베이스에서 사용자 조회
   return dataRepository.findById(id)
         .flatMap(existingUser -> {
            // 기존 사용자가 있으면 업데이트 수행
            existingUser.setName(userUpdateRequestDto.getName());
            // 다시 데이터베이스에 저장
            return dataRepository.save(existingUser);
         });
}

 

과 같이 Mono<User> 를 리턴 하는데 포스트맨으로 응답이 json 형태로 옵니다.
저는 User를 리턴한게 아닌 Mono<User> 를 리턴한건데 어떻게 포스트맨이 별도의 처리 없이 Mono 안의 User 값을 받을 수 있나요?

Mono<User> userMono = webClient.get() .uri("/user/{id}", userId) .retrieve() .bodyToMono(User.class);

위와 같은 코드를 보았는데 이 경우 Mono<User> userMono로 받게 되던데 결국 리턴은 Mono<User> 가 맞는거 같은데
포스트맨이 어떻게 User 값을 바로 가져다 썼는지 이해가 잘 안가서 질문 올립니다.

+ 추가로 mono나 flux는 subscribe()를 해줘야 동작을 한다고 하셨었는데 subscribe()를 적지 않았는데 어떻게 update가 동작한건지 궁금합니다.

답변 1

답변을 작성해보세요.

1

안녕하세요?

두 가지 질문을 주신걸로 여겨지는데요.

주신 질문에 간단하게나마 답변을 드리도록 하겠습니다.

 

  1. 저는 User를 리턴한게 아닌 Mono<User> 를 리턴한건데 어떻게 포스트맨이 별도의 처리 없이 Mono 안의 User 값을 받을 수 있나요?

--> Postman 뿐만 아니라 Spring에서 지원하는 RestTemplate 같은 Rest Client를 사용해서 Spring WebFlux의 엔드포인트를 호출해도 응답 데이터를 전달 받을 수 있습니다. 즉, 말씀하신대로 Spring WebFlux의 엔드포인트에서는 Mono<User>를 리턴하지만 클라이언트 쪽에서는 json으로 전달 받을 수 있습니다.

이렇게 전달 받을 수 있는 이유는 Postman이나 RestTemplate 같은 클라이언트 툴이 Blocking I/O 방식으로 동작하기 때문인데요. 클라이언트 쪽에서 Non-Blocking I/O를 지원하지 않는다면 서버 쪽에서는 내부적으로 Blocking I/O 방식으로 동작한다고 보시면 될 것 같습니다.

어떻게 Mono<User>를 리턴 타입으로 지정했는데, json을 전달 받을 수 있는지에 관해서는 두 번째 질문과도 연관이 있는데요.

Spring WebFlux 프레임워크 내부에서 subscribe()가 호출이 되는게 맞습니다.

다만, subscribe()가 언제 호출되는지 시점의 차이가 있는데 RestTemplate 같이 Non-Blocking I/O를 지원하지 않는 Rest Client를 사용할 경우에는 서버 쪽 Spring WebFlux 내부에서부터 subscribe() 호출이 시작된다고 보시면 될 것 같구요.
Non-Blocking I/O를 지원하는 WebClient를 이용하면 WebClient 쪽 즉, 클라이언트 쪽에서 subscribe()를 호출해야지만 서버 쪽 엔드포인트를 호출합니다.

이 말은 subscribe() 호출 시작이 클라이언트에서부터 시작한다는 의미와 같습니다.

 

  1. 추가로 스프링웹 플럭스가 컨트롤러쪽으로 Mono 나 Flux 타입이 리턴되면 subscribe() 를 자동으로 해준다는데 이게 맞는말인지 궁금합니다


    --> 위에서 말씀 드렸지만 Spring WebFlux 프레임워크 내부에서 subscribe()를 해준다고 보시면 되는데, Rest Client가 Non-Blocking을 지원하면 클라이언트 쪽에서 subscribe()를 호출 해야지만 서버 쪽에서도 subscribe()가 호출되어서 Reactor Sequence가 동작을 합니다. 테스트 해 보시면 아시겠지만 WebClient로 서버쪽 엔드 포인트를 호출해서 response body 응답을 mono로 변환하는 부분(bodyToMono()) 다음 코드 체인으로 subscribe()를 호출하지 않으면 서버쪽 엔드 포인트를 호출하지 않습니다.

    답변 드린 내용이 도움이 되셨으면 좋겠습니다.
    감사합니다.


verdelet님의 프로필

verdelet

질문자

2024.01.30

안녕하세요 강사님

마지막으로 하나만 여쭤 봐도 될까요..?

강의에서 책 조회 서비스를 예를 드셨었는데

유저(클라이언트가) 책 조회를 하게 되면 본 서버가 하위 서버에게 각각 책이 있는지 조회를 요청 하는

그림을 보여주셨었는데 본서버는 webclient로 하위 서버에게 Non-Blocking 비동기요청을 하게되고

하위 서버는 웹플럭스를 사용하여 응답을 줘서 Non-Blocking 리액티브 비동기가 맞다고 생각을 했습니다.

하위 서버로 부터 조회정보를 받은 본 서버는 유저에게 이제 응답을 줘야하는데

유저에게 주는 응답은 blocking 방식으로 줘도 되는것이 맞는지 궁금합니다.

만약 비동기 Non-Blocking 로 응답을 줘야 한다면 유저가 도서 조회 버튼을 누를때 비동기로 요청 되도록 fetch 같은걸로 요청을 해야하는 건가요..?


늦은 시간에 답변 주셔서 감사드립니다.

네, 클라이언트 쪽에서도 Non-Blocking을 지원해야 Fully Non-blocking하게 동작합니다.

그래서 Spring WebFlux에서는 RestTemplate을 사용하는 것 보다 WebClient를 사용하는 것을 권장하고 있습니다. 적은 트래픽에서야 큰 차이가 나지 않을 수 있지만 대량의 트랙픽이 발생할 경우에는 Blocking 포인트가 늘어나는 만큼 성능에 악영향을 미칠테니까요.

그래서 Non-Blocking 애플리케이션에서 내부적으로 Blocking call이 발생하는 구간이 없는지를 점검하는 blockhound 같은 오픈 소스도 존재합니다.

verdelet님의 프로필

verdelet

질문자

2024.01.30

답변 감사드립니다.

`하위 서버로 부터 조회정보를 받은 본 서버는 유저에게 이제 응답을 줘야하는데

유저에게 주는 응답은 blocking 방식으로 줘도 되는것이 맞는지 궁금합니다.

만약 비동기 Non-Blocking 로 응답을 줘야 한다면 유저가 도서 조회 버튼을 누를때 비동기로 요청 되도록 fetch 같은걸로 요청을 해야하는 건가요..?`
--> 최종 클라이언트 즉, 사용자인데요. 사용자에게 Blocking 방식으로 응답을 주든 Non-Blocking 방식으로 주든 애플리케이션이 서비스를 제공하는데 문제가 없는지 상황에 맞게 분석 또는 테스트해 보시고 결정하시면 됩니다. 다만, Spring WebFlux를 사용하는 근본적인 이유는 대량의 트래픽을 효과적으로 처리하기 위해 Fully Non-Blocking하게 동작하도록 하는 것이라서 Blocking call이 최대한 개입되지 않도록 하는게 맞다고 생각합니다.

사용자 쪽이 javascript를 사용하는 웹 앱을 말씀하시는 것 같은데 fetch API를 사용하시면서 async로 동작하게 해도 되지만 Javascript에서 rx.js 같은 라이브러리를 이용하면 데이터 처리를 조금 더 효과적으로 처리할 수 있다고 생각합니다.

verdelet님의 프로필

verdelet

질문자

2024.01.30

질문이 두서 없어서 계속 글 수정 중에 답변을 주셔서 못 보셨을 줄 알았는데 다시 확인해 주셨네요 상세한 담변 정말 감사드립니다