为何现在响应式编程在业务开发微服务开发不普及
Posted 我的编程喵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为何现在响应式编程在业务开发微服务开发不普及相关的知识,希望对你有一定的参考价值。
为何现在响应式编程在业务开发微服务开发不普及
主要因为数据库 IO,不是 NIO。
不论是Java自带的Future框架,还是 Spring WebFlux,还是 Vert.x,他们都是一种非阻塞的基于Ractor模型的框架(后两个框架都是利用netty实现)。
在阻塞编程模式里,任何一个请求,都需要一个线程去处理,如果io阻塞了,那么这个线程也会阻塞在那。但是在非阻塞编程里面,基于响应式的编程,线程不会被阻塞,还可以处理其他请求。举一个简单例子:假设只有一个线程池,请求来的时候,线程池处理,需要读取数据库 IO,这个 IO 是 NIO 非阻塞 IO,那么就将请求数据写入数据库连接,直接返回。之后数据库返回数据,这个链接的 Selector 会有 Read 事件准备就绪,这时候,再通过这个线程池去读取数据处理(相当于回调),这时候用的线程和之前不一定是同一个线程。这样的话,线程就不用等待数据库返回,而是直接处理其他请求。这样情况下,即使某个业务 SQL 的执行时间长,也不会影响其他业务的执行。
但是,这一切的基础,是 IO 必须是非阻塞 IO,也就是 NIO(或者 AIO)。官方JDBC没有 NIO,只有 BIO 实现。这样无法让线程将请求写入链接之后直接返回,必须等待响应。但是也就解决方案,就是通过其他线程池,专门处理数据库请求并等待返回进行回调,也就是业务线程池 A 将数据库 BIO 请求交给线程池B处理,读取完数据之后,再交给 A 执行剩下的业务逻辑。这样A也不用阻塞,可以处理其他请求。但是,这样还是有因为某个业务 SQL 的执行时间长,导致B所有线程被阻塞住队列也满了从而A的请求也被阻塞的情况,这是不完美的实现。真正完美的,需要 JDBC 实现 NIO。
Java 自带的 Future 框架可以这么用JDBC:
@GetMapping
public DeferredResult<Result> get() {
DeferredResult<Result> deferredResult = new DeferredResult<>();
CompletableFuture.supplyAsync(() -> {
return 阻塞数据库IO;
//dbThreadPool用来处理阻塞的数据库IO
}, dbThreadPool).thenComposeAsync(result -> {
//spring 的 DeferredResult 来实现异步回调写入结果返回
deferredResult.setResult(result);
});
return deferredResult;
}
WebFlux 也可以使用阻塞JDBC,但是同理:
@GetMapping
public Mono<Result> get() {
return Mono.fromFuture(CompletableFuture.supplyAsync(() -> {
return 阻塞数据库IO;
//dbThreadPool用来处理阻塞的数据库IO
}, dbThreadPool));
}
Vert.x 也可以使用阻塞的JDBC,也是同理:
@GetMapping
public DeferredResult<Result> get() {
DeferredResult<Result> deferredResult = new DeferredResult<>();
getResultFromDB().setHandler(asyncResult -> {
if (asyncResult.succeeded()) {
deferredResult.setResult(asyncResult.result());
} else {
deferredResult.setErrorResult(asyncResult.cause());
}
});
return deferredResult;
}
private WorkerExecutor dbThreadPool = vertx.createSharedWorkerExecutor("DB", 16);
private Future<Result> getResultFromDB() {
Future<Result> result = Future.future();
dbThreadPool.executeBlocking(future -> {
return 阻塞数据库IO;
}, false, asyncResult -> {
if (asyncResult.succeeded()) {
result.complete(asyncResult.result());
} else {
result.fail(asyncResult.cause());
}
});
return result;
}
相当于通过另外的线程池(当然也可以通过原有线程池,反正就是要用和请求不一样的线程,才能实现回调,而不是当次就阻塞等待),封装了阻塞 JDBC IO。
但是,这样几乎对数据库IO主导的应用性能没有提升,还增加了线程切换,得不偿失。所以,需要使用真正实现了 NIO 的数据库客户端。目前有这些 NIO 的 JDBC 客户端,但是都不普及:
Vert.x 客户端:https://vertx.io/docs/vertx-jdbc-client/java/
r2jdbc 客户端:http://r2dbc.io/
Jasync-sql 客户端:https://github.com/jasync-sql/jasync-sql
每日一刷,轻松提升技术,斩获各种offer:
以上是关于为何现在响应式编程在业务开发微服务开发不普及的主要内容,如果未能解决你的问题,请参考以下文章