webflux不支持mysql_WebFlux学习时常见的问题

前言

只有光头才能变强。

开局再来一张图,内容全靠编:

AAffA0nNPuCLAAAAAElFTkSuQmCC

这篇主要写写我初学时对WebFlux的一些疑问,不知道大家在看上一篇文章的时候有没有相应的问题呢?

一、本来就能实现异步非阻塞,为啥要用WebFlux?

相信有过相关了解的同学都知道,Servlet 3.1就已经支持异步非阻塞了。

我们可以以自维护线程池的方式实现异步说白了就是Tomcat的线程处理请求,然后把这个请求分发到自维护的线程处理,Tomcat的请求线程返回@WebServlet(value = "/nonBlockingThreadPoolAsync", asyncSupported = true)

public class NonBlockingAsyncHelloServlet extends HttpServlet {

private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 200, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100));

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

AsyncContext asyncContext = request.startAsync();

ServletInputStream inputStream = request.getInputStream();

inputStream.setReadListener(new ReadListener() {

@Override

public void onDataAvailable() throws IOException {

}

@Override

public void onAllDataRead() throws IOException {

executor.execute(() -> {

new LongRunningProcess().run();

try {

asyncContext.getResponse().getWriter().write("Hello World!");

} catch (IOException e) {

e.printStackTrace();

}

asyncContext.complete();

});

}

@Override

public void onError(Throwable t) {

asyncContext.complete();

}

});

}

}

流程图如下:

AAffA0nNPuCLAAAAAElFTkSuQmCC异步非阻塞的图

上面的例子来源:https://www.cnblogs.com/davenkin/p/async-servlet.html

简单的方式,我们还可以使用JDK 8 提供的CompletableFuture类,这个类可以方便的处理异步调用。protected void doGet(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

long t1 = System.currentTimeMillis();

// 开启异步

AsyncContext asyncContext = request.startAsync();

// 执行业务代码(doSomething 指的是处理耗费时间长的方法)

CompletableFuture.runAsync(() -> doSomeThing(asyncContext,

asyncContext.getRequest(), asyncContext.getResponse()));

System.out.println("async use:" + (System.currentTimeMillis() - t1));

}

要处理复杂的逻辑时,无论是回调或 CompletableFuture在代码编写上都会比较复杂(代码量大,不易于看懂),而WebFlux使用的是Reactor响应式流,里边提供了一系列的API供我们去处理逻辑,就很方便了。

AAffA0nNPuCLAAAAAElFTkSuQmCC回调地狱

更重要的是:WebFlux使用起来可以像使用SpringMVC一样,能够大大减小学习成本

WebFlux也可以使用Functional Endpoints方式编程,总的来说还是要比回调/CompletableFuture要简洁和易编写。

AAffA0nNPuCLAAAAAElFTkSuQmCC无缝与SpringMVC的技术使用

值得一提的是:如果Web容器使用的是Tomcat,那么就是使用Reactor桥接的servlet async api

如果Web容器是Netty,那么就是使用的Netty,天生支持Reactive

官方的推荐是使用Netty跑WebFlux

二、WebFlux性能的问题

我们从上篇文章中就发现,浏览器去调用处理慢的接口,无论是该接口是同步的,还是说是异步的,返回到浏览器的时间都是一致的。同步:服务器接收到请求,一个线程会处理请求,直到该请求处理完成,返回给浏览器

异步:服务器接收到请求,一个线程会处理请求,然后指派别的线程处理请求,请求的线程直接空闲出来。

官网也说了:Reactive and non-blocking generally do not make applications run faster

使用异步非阻塞的好处就是:The key expected benefit of reactive and non-blocking is the ability to scale with a small, fixed number of threads and less memory.That makes applications more resilient under load, because they scale in a more predictable way

好处:只需要在程序内启动少量线程扩展,而不是水平通过集群扩展。异步能够规避文件IO/网络IO阻塞所带来的线程堆积。

下面来看一下针对相同的请求量,同步阻塞和异步非阻塞的吞吐量和响应时长对比:

AAffA0nNPuCLAAAAAElFTkSuQmCC吞吐量和RT对比

注:请求量不大时(3000左右),同步阻塞多线程处理请求,吞吐量和响应时长都没落后。(按道理WebFlux可能还要落后一些,毕竟多做了一步处理-->将请求委派给另一个线程去做处理

请求量大时,线程数不够用,同步阻塞(MVC)只能等待,所以吞吐量要下降,响应时长要提高(排队)。Spring WebFlux在应对高并发的请求时,借助于异步IO,能够以少量而稳定的线程处理更高吞吐量的请求,尤其是当请求处理过程如果因为业务复杂或IO阻塞等导致处理时长较长时,对比更加显著。

三、WebFlux实际应用

WebFlux需要非阻塞的业务代码,如果阻塞,需要自己开线程池去运行。WebFlux什么场景下可以替换SpringMVC呢?想要内存和线程数较少的场景

网络较慢或者IO会经常出现问题的场景SpringMVC和WebFlux更多的是互补关系,而不是替换。阻塞的场景该SpringMVC还是SpringMVC,并不是WebFlux出来就把SpringMVC取代了。

AAffA0nNPuCLAAAAAElFTkSuQmCCSpringMVC和WebFlux

如果想要发挥出WebFlux的性能,需要从Dao到Service,全部都要是Mono和Flux,目前官方的数据层Reactive框架只支持Redis,Mongo等几个,没有JDBC。

目前对于关系型数据库,Pivotal团队开源出R2DBC(Reactive Relational Database Connectivity),其GitHub地址为:https://github.com/r2dbc

目前R2DBC支持三种数据源:PostgreSQL

H2

Microsoft SQL Server

总的来说,因为WebFlux是响应式的,要想发挥出WebFlux的性能就得将代码全改成响应式的,而JDBC目前是没支持的(至少MySQL还没支持),而响应式的程序不好调试和编写(相对于同步的程序),所以现在WebFlux的应用场景还是相对较少的。

所以,我认为在网关层用WebFlux比较合适(本来就是网络IO较多的场景)

现在再回来看Spring官网的图,是不是就更亲切了?

AAffA0nNPuCLAAAAAElFTkSuQmCCSpring官网介绍图

参考资料:https://blog.lovezhy.cc/2018/12/29/webflux性能问题

四、有必要学Functional Endpoints 编程模式吗?

前面也提到了,WebFlux提供了两种模式供我们使用,一种是SpringMVC 注解的,一种是叫Functional Endpoints的Lambda-based, lightweight, and functional programming model

总的来看,就是配合Lambda和流式编程去使用WebFlux。如果你问我:有必要学吗?其实我觉得可以先放着。我认为现在WebFlux的应用场景还是比较少,等真正用到的时候再学也不是什么难事,反正就是学些API嘛~

有Lambda表达式和Stream流的基础,等真正用到的时候再学也不是啥问题~

以下是通过注解的方式来使用WebFlux的示例:

AAffA0nNPuCLAAAAAElFTkSuQmCC通过注解的方式来使用WebFlux

以下是通过Functional Endpoints的方式来使用WebFlux的示例:

路由分发器,相当于注解的GetMapping…

AAffA0nNPuCLAAAAAElFTkSuQmCC路由分发器

UserHandler,相当于UserController:

AAffA0nNPuCLAAAAAElFTkSuQmCCUserHanler

要在Spring WebFlux中使用R2DBC连接MySQL并集成Flyway,可以按照以下步骤进行操作: 1. 在pom.xml中添加所需的依赖项: ```xml <!-- Spring WebFlux --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- R2DBC MySQL 驱动 --> <dependency> <groupId>dev.miku</groupId> <artifactId>r2dbc-mysql</artifactId> <version>0.8.2.RELEASE</version> </dependency> <!-- Flyway --> <dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> </dependency> ``` 2. 在application.properties中配置R2DBC连接和Flyway: ```properties # R2DBC MySQL 连接配置 spring.r2dbc.url=r2dbc:mysql://localhost:3306/test spring.r2dbc.username=root spring.r2dbc.password=root # Flyway 配置 flyway.locations=classpath:db/migration flyway.clean-disabled=false flyway.baseline-on-migrate=true ``` 3. 创建数据库迁移脚本文件,存放在`src/main/resources/db/migration`目录下。例如,创建一个名为`V1__init.sql`的脚本文件,用于初始化数据库: ```sql CREATE TABLE `user` ( `id` INT PRIMARY KEY, `name` VARCHAR(50) NOT NULL, `age` INT NOT NULL ); ``` 4. 在Spring Boot应用程序中创建一个数据访问对象(DAO)来处理与数据库的交互。可以使用R2DBC提供的`DatabaseClient`或Spring Data R2DBC来简化数据库访问。 5. 启动应用程序,Flyway将自动执行数据库迁移脚本,初始化数据库。 注意:R2DBC是非阻塞的数据库访问方式,与传统的JDBC和Spring Data JPA不同,需要使用异步的方式进行操作。确保代码中的异步操作正确处理。 希望对你有所帮助!如有其他问题,请随提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值