本文是本人在知乎提问 spring webflux现在看来是否成功? 下的回答,其他回答也很精彩,如果感兴趣可以查看

现在基于 spring web 的同步微服务有一个非常大的缺陷就是:相对于基于 spring-webflux 的异步微服务,基于 spring-web 的同步微服务没有很好的处理客户端有请求超时配置的情况。当客户端请求超时时,客户端会直接返回超时异常,但是调用的服务端任务,在基于 spring-web 的同步微服务并没有被取消,基于 spring-webflux 的异步微服务是会被取消的。目前,还没有很好的办法在同步环境中可以取消这些已经超时的任务。

Spring-weflux 目前最大的问题,在于很多框架,包括 JDK 本身,有很多基于 Thread 的 Context,例如 Thread local 这种。还有就是 Java Log 框架的 MDC 的实现,一般都是基于 ThreadLocal 的 Map.还有就是像 redisson 的分布式锁,它让每个线程生成唯一id并和线程绑定,解锁的时候会检查。 但是这种设计,与 Spring-Webflux 的 Context 很难兼容。可以看看 Spring cloud sleuth 在 Spring-Webflux 中加入链路信息上下文,并保持,有多麻烦,而且,还有不少的 bug 和漏掉的点,参考:

还有一点比较麻烦,就是和现有的各种阻塞锁的设计,不兼容,因为响应式编程需要非阻塞。这需要重构成队列排序消费来解决并发竞争,工作量也很大。

然后就是官方数据库 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 本身的 Project Loom,我简单研究过他的实现原理:

简单总结即:在虚拟线程中运行的 Java 同步网络 API 会将底层原生 Socket 切换到非阻塞模式。当 Java 代码启用一个 I/O 请求并且这个请求没有立即完成(原生 socket 返回 EAGAIN - 代表"未就绪"/"会阻塞")的时候,这个底层 socket 会被注册到一个 JVM 内部事件通知机制(Poller),并且虚拟线程会被 parked。当底层 I/O 操作就绪的时候(有相关事件会到达 Poller),虚拟线程会 unparked 并且底层的 Socket 操作会被重试处理。同步 Java 网络 API 已经被重新实现,相关的 JEP 包括 JEP 353 和 JEP 373. 在虚拟线程中运行时,不能立即完成的 I/O 操作将导致虚拟线程被 parked 。当 I/O 就绪时,虚拟线程将被 unparked。这个实现相对于当前的异步非阻塞 I/O 实现代码来看,更加简单易用,隐藏了很多业务不关心的实现细节。

Project Loom 解决了主要的网络 IO 阻塞问题,并且基本不用改现有代码就能实现纤程,用阻塞的代码风格实现非阻塞的代码(而且和现在的基于 Thread 的上下文框架兼容)。是目前的 Java 架构师 Goetz 最看重的特性之一,目前 Java 17 的很多新特性其实就是为这个 Project Loom 的发布铺路,可以看看 Nicolai 和 Goetz 大神的这个视频,从 19:17 秒开始:

Brian Goetz: "I think Project Loom is going to kill Reactive Programming"(哈哈,有点过于乐观带节奏了,不过值得观望)

不过,虽然期望中是仅需要下面这种代码就可以把现有的线程和线程池替换成虚拟线程:

Thread thread = Thread.ofVirtual().name("duke").unstarted(runnable);
ThreadFactory factory = Thread.ofVirtual().factory(); ExecutorService b = Executors.newVirtualThreadPool();

但是还有很多问题需要解决:

  1. ThreadLocal 相关的类,由于虚拟线程会无限制的生成,ThreadLocal 的生成也需要重新设计:首先是很多 JDK 中的框架基于 ThreadLocal 的 Probe 实现,例如 ThreadLocalRandom 的初始 Seed。第二是 ThreadLocal 的使用可能会导致 GC 压力增大,因为虚拟线程可以无限制的生成。
  2. 依然阻塞实际线程的地方:在同步锁的阻塞还是会阻塞实际的线程,还有文件 IO 等。
  3. 修改以上带来的 bug 以及安全问题,由于这些修改动了 JDK 的一些框架的根本,没有经过实际线上应用之前,仅凭单元测试和压测可能很难发现一些细节问题。

不过,现在的 Java 已经在为 Project loom 铺路了,例如:

微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer

关于 Spring-WebFlux 的一些想法的更多相关文章

  1. Spring Webflux: Kotlin DSL [片断]

    原文链接:https://dzone.com/articles/spring-webflux-kotlin-dsl-snippets 作者:Biju Kunjummen 译者:Jackie Tang ...

  2. Spring WebFlux开门迎客,却来了一位特殊客人

    话说Spring WebFlux已经出现有一段时间了,但是知道他的人并不是很多.这让他很是闷闷不乐. 还有更惨的是,那些敢于吃螃蟹的人在尝试了他之后,有的竟把代码重新改回到Spring MVC的同步模 ...

  3. 爸爸又给Spring MVC生了个弟弟叫Spring WebFlux

    情景引入 很早之前,Java就火起来了,是因为它善于开发和处理网络方面的应用. Java有一个爱好,就是喜欢制定规范标准,但自己又不善于去实现. 反倒是一些服务提供商使用它的规范标准来制造应用服务器而 ...

  4. Spring WebFlux 响应式编程学习笔记(一)

    各位Javaer们,大家都在用SpringMVC吧?当我们不亦乐乎的用着SpringMVC框架的时候,Spring5.x又悄(da)无(zhang)声(qi)息(gu)的推出了Spring WebFl ...

  5. Spring WebFlux 要革了谁的命?

    Spring WebFlux 要革了谁的命?  mp.weixin.qq.com 托梦 Java国王昨晚做了一个梦. 梦中有个白胡子老头儿,颇有仙风道骨, 告诉他说:“你们Java啊,实在是太弱了,连 ...

  6. 基于Angular和Spring WebFlux做个小Demo

    前言 随着Spring Boot2.0正式发布,Spring WebFlux正式来到了Spring Boot大家族里面.由于Spring WebFlux可以通过更少的线程去实现更高的并发和使用更少的硬 ...

  7. Spring WebFlux, 它是一种异步的, 非阻塞的, 支持背压(Back pressure)机制的Web 开发WebFlux 支持两种编程风(姿)格(势) 使用@Controller这种基于注解

    概述 什么是 Spring WebFlux, 它是一种异步的, 非阻塞的, 支持背压(Back pressure)机制的Web 开发框架. 要深入了解 Spring WebFlux, 首先要了知道 R ...

  8. 朱晔和你聊Spring系列S1E5:Spring WebFlux小探

    阅读PDF版本 本文会来做一些应用对比Spring MVC和Spring WebFlux,观察线程模型的区别,然后做一下简单的压力测试. 创建一个传统的Spring MVC应用 先来创建一个新的web ...

  9. 【SFA官方翻译】Spring WebFlux和Spring Cloud进行响应式微服务开发

    源码,修正一些错误: https://github.com/bigben0123/sample-spring-cloud-webflux 原创 SpringForAll社区 2018-05-18 作者 ...

  10. 初识Spring Webflux

    Important to know is that there are two ways to use Spring Webflux. One using annotations, which is ...

随机推荐

  1. android studio 生成aar和引用aar

    以android studio 2.0正式版为例 1.aar包是Android studio下打包android工程中src.res.lib后生成的aar文件,aar包导入其他android stud ...

  2. 随录、EJB和JTA

    说道JTA(Java Transction Api),即事务的一种. 事务:说白了就是一组原子操作,是为了保证数据的安全性. 它,分为三类:JDBC事务,JTA事务,还有容器事务. JDBC是由Con ...

  3. oracle 拆分字符串

    WITH t AS (SELECT '1-2-3-4' a FROM dual)SELECT Regexp_Substr(a, '[^-]+', 1, LEVEL) i FROM tCONNECT B ...

  4. vue2 页面路由

    vue官方文档 src/views/Login.vue <template> <div> <h2>登录页</h2> </div> </ ...

  5. hadoop accesscontrolException

    DFS loaction: /tmp 文件下的 hadoop-haoop/mapred/system报 AccessControlException. 解决: bin/hadoop fs -chmod ...

  6. Cnblog博客美化

    具体的使用教程文档在这里 BNDong/Cnblogs-Theme-SimpleMemory 简要的操作如下: 博客园 - 管理 - 设置 值得注意得是: 要想JS代码要申请才可以使用 博客侧边栏 可 ...

  7. 网络协议之:基于UDP的高速数据传输协议UDT

    目录 简介 UDT协议 UDT的缺点 总结 简介 简单就是美.在网络协议的世界中,TCP和UDP是建立在IP协议基础上的两个非常通用的协议.我们现在经常使用的HTTP协议就是建立在TCP协议的基础上的 ...

  8. HGAME2021 week3 pwn writeup

    一共放出五道题,都不是很难. blackgive 考栈转移,值得注意的一点是转移过去先填充几个ret,因为如果直接在转移过去的地方写rop链,执行起来会覆盖到上面的一些指针,导致程序不能正常输入和输出 ...

  9. Windows 任务计划部署 .Net 控制台程序

    Windows 搜索:任务计划程序 创建任务 添加任务名称 设置触发器:这里设置每10分钟执行一次 保存之后显示 此任务会从每天的 0:10:00 执行第一次后一直循环下去. 在操作选项卡下,选择启动 ...

  10. Frequency函数(Excel函数集团)

    此处文章均为本妖原创,供下载.学习.探讨! 文章下载源是Office365国内版1Driver,如有链接问题请联系我. 请勿用于商业!谢谢 下载地址:https://officecommunity-m ...