前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为何现在响应式编程在业务开发微服务开发不普及

为何现在响应式编程在业务开发微服务开发不普及

作者头像
干货满满张哈希
发布2021-04-12 11:11:21
6550
发布2021-04-12 11:11:21
举报
文章被收录于专栏:干货满满张哈希

为何现在响应式编程在业务开发微服务开发不普及

主要因为数据库 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:

代码语言:javascript
复制
@GetMapping
public DeferredResult get() {
DeferredResult deferredResult = new DeferredResult<>();
CompletableFuture.supplyAsync(() -> {
            return 阻塞数据库IO;
        //dbThreadPool用来处理阻塞的数据库IO
        }, dbThreadPool).thenComposeAsync(result -> {
    //spring 的 DeferredResult 来实现异步回调写入结果返回
    deferredResult.setResult(result);
});
return deferredResult;
}

WebFlux 也可以使用阻塞JDBC,但是同理:

代码语言:javascript
复制
@GetMapping
public Mono get() {
return Mono.fromFuture(CompletableFuture.supplyAsync(() -> {
            return 阻塞数据库IO;
        //dbThreadPool用来处理阻塞的数据库IO
        }, dbThreadPool));
}

Vert.x 也可以使用阻塞的JDBC,也是同理:

代码语言:javascript
复制
@GetMapping
public  DeferredResult get() {
DeferredResult 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 getResultFromDB() {
    Future 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 客户端,但是都不普及:

  1. Vert.x 客户端:https://vertx.io/docs/vertx-jdbc-client/java/
  2. r2jdbc 客户端:http://r2dbc.io/
  3. Jasync-sql 客户端:https://github.com/jasync-sql/jasync-sql

每日一刷,轻松提升技术,斩获各种offer:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/02/08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档