하나의 커다란 서비스와 저장소로 구성된 기존의 모놀로식 아키텍쳐 환경은 여러 문제점들이 있었다.

  • 하나의 모듈이 변경되어도 전체 서버를 배포해야 했다.
  • 작은 기능의 문제점도 곧 서버 전체의 문제점이 되었다.

 

이러한 단점을 극복하기 위해 MSA( Microservice Architecture )가 탄생했다. ( Netflix에서 처음 도입하면서 유명해짐 )

하나의 커다란 서비스는 독립적인 작은 단위의 모듈로 쪼개지게 되었고, 기능의 추가나 확장은 모듈을 통해서 이루어졌다.

 

그런데 모놀로식 아키텍쳐 환경이 MSA 환경으로 변화하면서 새로운 문제가 생기기 시작했다.

기존의 모놀로식 아키텍쳐 환경에서는 스레드 풀을 이용해 동기식 프로그래밍의 blocking을 감당할 수 있었고, 

단일 애플리케이션 내부에서 정보 교환이 일어나기 때문에 blocking되는 시간이 그리 길지 않았었다.

 

이런 모놀로식 아키텍쳐에서 하나의 큰 서비스가 작은 단위의 독립된 모듈로 쪼개지면서, 단일 애플리케이션 내부에서 일어나던 정보교환이 네트워크를 통한 모듈과 모듈간 정보교환으로 바뀌게 되었고, 이로인해 다음과 같은 문제가 발생했다.

  • blocking 시간이 길어지면 응답을 기다리는데 스레드를 모두 소진해버릴 수 있다.
  • 타임아웃이 발생할 정도의 지연이 발생하면 다른 모듈에도 영향을 주어 전체 시스템이 다운될 수 있다.

 

이러한 문제점들을 극복하기 위해 MSA 환경에 들어서면서 부각되기 시작한게 이벤트 루프를 이용한 비동기 프로그래밍이다.

Spring 생태계에서도 버전 5부터 도입된 WebFlux를 통해 비동기 프로그래밍을 본격적으로 도입하였다.

 

 

기존의 Spring Framework ( Spring MVC )


기존에 사용되던 Spring MVC 애플리케이션의 형태는 다음과 같다.

  1. XML 기반의 환경설정을 한다.
  2. DispatcherServlet 기반의 코드를 WAR로 패키징하여 WAS의 docRoot에 배포한 후 기동한다.

 

이는 다음과 같은 문제를 야기했다.

  • 관리의 이원화
        애플리케이션의 설정과 WAS의 설정을 별도로 관리한다.

  • 배포 및 설정의 불편
        WAS 중지 -> WAR 패키지 배포 -> WAS 기동의 단계가 필요하다.
        XML 기반의 설정은 애플리케이션을 기동해보기 전까지는 설정이 맞는지 틀렸는지 알 수 없다.

  • WAS에 의존적인 구조
        Servlet 기반이기 때문에 WAS를 벗어나 단독으로 실행이 불가능하다.

 

위와 같은 문제점들은 MSA 환경에 들어서면서 치명적인 단점으로 부각되었고, 이를 극복하기 위해 다음과 같은 발전을 이룬다.

  • Spring 버전 3에서 JavaConfig, 애너테이션 기반의 설정을 도입
  • Spring 버전 4에서 Spring Boot의 AutoConfig + WAS 엔진 내장으로 단일 JAR 파일로 패키징하여 배포가 가능해짐

 

 

Spring WebFlux


Spring WebFlux의 특징은 다음과 같다.

  • Servlet과는 전혀 관계없이 만들어졌기 때문에, WAS에 의존적이지 않다.
  • 기본 설정은 Netty( reactor-netty )를 기반으로 한다.
  • Project Reactor를 통해서 Reactive Programming을 지원한다. ( Project Reactor는 Reactive Streams의 구현체 )

 

Spring WebFlux는 2가지 라우팅 방식을 사용할 수 있다.

// 애너테이션 기반 라우팅
@GetMapping("/hello")
@ResponseBody
public Mono<String> helloController() {
    return helloService.getHello();
}

// 함수 기반 라우팅
@Bean
public RouterFunction<ServerResponse> routes(DemoHandller demoHandler) {
    return RouterFunctions.route(RequestPredicates.GET("/hello"), demoHandler::getHello);
}

 

Spring MVC와 WebFlux는 전체적인 코드의 생김새는 같지만, 한 가지, 반환형이 다르다.

기존의 Spring MVC는 Plain Object를 반환했다면, Spring WebFlux는 반드시 Publisher Object로 감싸서 반환해야 한다.

 

Spring WebFlux의 전체적인 예를 살펴보자.

DemoRouter.java

@Configuration
public class DemoRouter {
    
    @Bean
    public RouterFunction<ServerResponse> routes(DemoHandler demoHandler) {
        return RouterFunctions
            .route(RequestPredicates.POST("/demo").and(contentType(APPLICATION_JSON)), demoHandler::postDemo);
    }
}

 

DemoHandler.java

@Slf4j
@Component
@RequiredArgsConstructor
public class DemoHandler {
    
    private final Validator validator;
    private final DemoService demoService;
    
    public Mono<ServerResponse> post(ServerRequest serverRequest) {
        Flux<DemoResponse> ret = demoService.post(
            serverRequest.bodyToFlux(DemoModel.class)
                .filter(demoModel -> {
                    Set<ConstraintViolation<DemoModel>> validationResult = validator.validate(demoModel);
                    
                    if (validationResult.isEmpty()) {
                        return true;
                    } else {
                        return false;
                    }
                })
        );
        
        return ServerResponse.ok().body(ret, DemoResponse.class);
    }
}

 

DemoService.java

@Service
public class DemoService {
    public Flux<DemoResponse> post(Flux<DemoModel> demoModelFlux) {
        return demoModelFlux
            .flatMap(demoModel -> {
                return Flux.just(new DemoResponse(demoModel, true));
            });
    }
}

 

DemoModel.java

@Data
public class DemoModel {

    @NotEmpty
    private String id;
    private Map<String, String> data;
    private LocalDateTime createDateTime = LocalDateTime.now();
    private double version = 1.0;
}

 

DemoResponse.java

@Data
public class DemoResponse {

    private DemoModel content;
    private boolean result;
}

 

위에서 Mono FluxPublisher Object이다.

 

 

참고자료)

https://d2.naver.com/helloworld/6080222