Spring5以后,新增了Webflux,异步非阻塞Web框架。
在SpringBoot第三篇的时候,简单介绍过WebFlux。
本篇,将从更细的粒度上,更全面的介绍下WebFlux。
WebFlux是脱离了传统阻塞式Servlet框架,所以,它不同于Spring MVC。
WebFlux是 Spring 5 的一个新模块。包含了响应式 HTTP、服务器推送事件和 WebSocket 的客户端和服务器端支持。
官方架构图
Webflux用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。
虽然Spring WebFlux不同于Spring MVC,但是Spring考虑到让我们更快的上手,它们的注解基本都是一样的。
SpringBoot WebMVC应用,都需要依赖spring-boot-starter-web ,内部包含Tomcat。
使用WebFlux不需要依赖spring-boot-starter-web 只依赖 spring-boot-starter-webflux 即可。
它的内部使用Netty来运行应用,Netty是基于异步和事件驱动的。
依赖图如下:
1、Maven
依赖清单对比:
- WebMVC(传统Servlet)
org.springframework.boot
spring-boot-starter-web
- WebFlux(异步非阻塞)
org.springframework.boot
spring-boot-starter-webflux
为了方便区分,在下面将使用servlet-web代替WebMVC,webflux-web代替WebFlux。
2、编码清单对比:
- servlet-web
@GetMapping("servletweb")
public Map servletweb(){
return Map.of("msg","servletweb");
}
- webflux-web
@GetMapping("webflux")
public Mono
它们的注解方式完全相同,WebFlux使用Mono进行修饰。
3、响应式Http
代码清单:
@GetMapping("webclient_demo")
public Mono
4、SSE
服务器推送事件(Server-Sent Events,SSE)允许服务器端不断地推送数据到客户端。相对于 WebSocket 而言,服务器推送事件只支持服务器端到客户端的单向数据传递。
看下面的例子,每一秒,向客户端推送一次数据。
代码清单:
@GetMapping("/random_numbers")
public Flux> randomNumbers() {
return Flux.interval(Duration.ofSeconds(1))
.map(seq -> Tuples.of(seq, ThreadLocalRandom.current().nextInt()))
.map(data -> ServerSentEvent.builder()
.event("random")
.id(Long.toString(data.getT1()))
.data(data.getT2())
.build());
}
访问接口:
对比方案
1、使用最简单的一个接口响应,各压测5次,每次1分钟
2、在接口中,增加一秒延迟,各压测5次,每次1分钟
3、在增加一秒延迟的基础上,压测5分钟
压测工具
JMeter
测试第一轮
压测结果
不加延迟,100并发,1分钟结果对比 |
||||
WebMVC |
WebFlux |
|||
序号 |
吞吐量 |
请求次数 |
吞吐量 |
请求次数 |
1 |
699.9/sec |
42099 |
764.3/sec |
46399 |
2 |
849.0/sec |
50985 |
775.3/sec |
46569 |
3 |
861.3/sec |
52252 |
845.6/sec |
50826 |
4 |
841.7/sec |
50534 |
750.2/sec |
45035 |
5 |
812.1/sec |
49779 |
760.7/sec |
45667 |
JVM对比图:
- WebMVC
- WebFlux
结果分析:
结合5次压测的结果,可以看出,在没有任何延迟情况下,WebMVC拥有更好的吞吐率。
结合JVM来看,差异最大的就是线程模块。
WebMVC的线程使用率最高时刻,接近200。当然,这是Tomcat默认的最大线程数。
而WebFlux的线程使用数,始终维持在20以内,接近10倍的差异。
测试第二轮
WebMVC和WebFlux各增加一秒延迟
压测结果
增加1秒延迟,100并发,1分钟结果对比 |
||||
WebMVC |
WebFlux |
|||
序号 |
吞吐量 |
请求次数 |
吞吐量 |
请求次数 |
1 |
97.8/sec |
5951 |
97.8/sec |
5965 |
2 |
97.9/sec |
5968 |
97.8/sec |
5964 |
3 |
97.8/sec |
5964 |
97.8/sec |
5966 |
4 |
97.8/sec |
5965 |
97.7/sec |
5947 |
5 |
97.8/sec |
5965 |
97.8/sec |
5967 |
JVM对比图:
- WebMVC
- WebFlux
结果分析:
增加了一秒延迟后,两边吞吐率结果几乎一致。
再看JVM对比结果,线程数仍然相差巨大。WebFlux使用的内存也明显更低。
测试第三轮
加长压测时间至5分钟
压测结果
增加1秒延迟,100并发,5分钟结果对比 |
||||
WebMVC |
WebFlux |
|||
序号 |
吞吐量 |
请求次数 |
吞吐量 |
请求次数 |
1 |
98.9/sec |
29711 |
98.9/sec |
29725 |
JVM对比图:
- WebMVC
- WebFlux
结果分析:
吞吐率一致,请求数WebFlux更多一些。
WebMVC线程数再次接近200的最大默认值。
WebFlux线程数依然保持在20左右。
WebFlux,诞生于2017年下半年,刚满周岁不久。
它是异步非阻塞的,所以它在高并发场景,拥有更好的性能,从上面的压测结果就可以看出。
但它尚是幼年,资料不像WebMVC那样丰富。
甚至,它还没有太好的办法支持MySQL,支持事物。
还有一些问题你可能需要深入源码去查看到底是为什么。
所以,在你没有足够野心的时候,最好不要轻易将线上的应用切换到WebFlux,在普通的场景下,它的性能不见得会更好。反而你要面对的是更难调试的异步程序和更多尚无优秀解决方案的问题模块。
但是无论怎么样,它是优秀的,它也是趋势。
博客内所有文章,每周从公众号同步一次。
文章源码均可从公众号获取。
如果您可以关注下,那就好了。