天天看点

Spring WebFlux响应式编程并发线程模型

Spring WebFlux响应式编程并发线程模型

概述

典型的web应用服务处理用户请求过程中,许多交互本质上是阻塞的,例如涉及数据库调用以获取或更新数据的交互,第三方接口调用等。每个线程一次处理一个请求,在多核平台上,在总体响应时间方面具有明显的优势。这种并发模型被称为Thread-Per-Request模型。

Spring WebFlux响应式编程并发线程模型

该模型并没有解决在单个线程中的大多数交互仍然是阻塞的这一事实。此外Java实现并发的本机线程在上下文切换方面也需要不少损耗。

随着web应用程序面临越来越多的请求,Thread-Per-Request模型效果是低于预期的。

因此,我们需要一个并发模型,它可以帮助我们用相对较少的线程数处理越来越多的请求。这是采用响应式编程的主要动机之一。

Reactive并发模型

Reactive编程带来的根本区别是异步性,流程运行从一系列同步操作转换为异步事件流。在异步非阻塞的环境中,可以实现更高的并发性和更好的资源利用率。

Spring WebFlux响应式编程并发线程模型

例如,从数据库的读取数据的操作在订阅后调用立即返回,不会阻塞调用线程,订阅者可以在收到事件通知后进行事件处理。

事件循环模型

响应式异步编程模型采用如下事件循环模型实现用更少的线程实现更高的并发性。

Spring WebFlux响应式编程并发线程模型

如图所示,事件循环的抽象设计,展示了响应式异步编程的思想:

  • 事件循环在单个线程中连续运行;
  • 事件循环顺序处理事件队列中的事件,并在向平台注册回调后立即返回;
  • 平台可以触发操作的完成,如数据库调用或外部服务调用;
  • 事件循环可以在操作完成通知触发回调,并将结果发送回调用者。

事件循环模型在许多平台中实现,包括Node.js、Netty和Ngnix。它们提供了比传统平台(如Apache HTTP Server、Tomcat或JBoss)更好的可扩展性。

Spring WebFlux框架

WebFlux是Spring在5.0版中添加的响应式Web框架,与Spring中的传统web框架是并行关系而不是取代。

Spring WebFlux响应式编程并发线程模型
  • Spring WebFlux通过函数路由扩展了传统的基于注释的编程模型;
  • 使底层HTTP运行时适应Reactive Streams API,使运行时具有互操作性;
  • 能够支持多种Reactive Runtime,包括Servlet 3.1+容器,如Tomcat、Reactor、Netty或Undertow;
  • 包括WebClient,用于HTTP请求的响应式非阻塞客户端。

Reactor Netty

Reactor Netty(https://netty.io/)是Spring Boot WebFlux默认的嵌入式服务器。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>           

可以看下Netty默认创建的线程:

Spring WebFlux响应式编程并发线程模型

除了服务器的正常线程外,Netty还生成了一组用于请求处理的工作线程,数量通常跟可用的CPU内核相关。让我们看看Netty是如何利用Java NIO实现事件循环:

Spring WebFlux响应式编程并发线程模型

EventLoopGroup管理一个或多个EventLoop,它必须持续运行。因此,不建议创建比可用内核数量更多的EventLoops。

EventLoopGroup还为每个新创建的Channel通道分配一个EventLoop。因此,在Channel的生命周期内,所有操作都由同一线程执行。

结论

通过Thread-Per-Request模型和Reactive并发模型的对比,涉及开发高效处理高并发请求的Web应用服务时,Spring Webflux是比较合适的选型。