本文是本人在知乎提问 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. spring定时任务执行两次

    最近用Spring的quartz定时器的时候,发现到时间后,任务总是重复执行两次,在tomcat或jboss下都如此. 打印出他们的hashcode,发现是不一样的,也就是说,在web容器启动的时候, ...

  2. centos7 自动同步时间

    rm -rf /etc/localtime ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime vim /etc/sysconfig/cloc ...

  3. UIButton总结

    UIButton 1. 功能 既能显示文字,又能显示图片(能显示2张图片,背景图片.内容图片) 长按高亮的时候可以切换图片\文字 直接通过addTarget...方法监听点击 2. 状态 normal ...

  4. 【编程思想】【设计模式】【行为模式Behavioral】观察者模式Observer

    Python转载版 https://github.com/faif/python-patterns/blob/master/behavioral/observer.py #!/usr/bin/env ...

  5. Linux下部署Java项目(jetty作为容器)常用脚本命令

    startup.sh #!/bin/bash echo $(basename $(pwd)) "jetty started" cd jetty nohup java -Xmx8g ...

  6. jstl中的choose标签

    <%@ page contentType="text/html;charset=UTF-8" language="java" %><%@ ta ...

  7. Django auth

    auth是django一个自带的用户验证系统,使用它可以减少我们的开发流程. 基本使用 大体流程: 自定义类 from django.contrib.auth.models import Abstra ...

  8. 莫烦python教程学习笔记——learn_curve曲线用于过拟合问题

    # View more python learning tutorial on my Youtube and Youku channel!!! # Youtube video tutorial: ht ...

  9. bcloud_bctf_2016(house of force)

    例行检查我就不放了,该程序是32位的程序 将程序放入ida中 进行代码审计 首先这这里有一个off by null 可以通过这里泄露出来第一个chunk的地址信息 这里也有同样的问题,我看ha1vk师 ...

  10. ciscn_2019_s_9

    很简单的一道题 例行检查 没有开启nx保护,就想到了shellcode来做 很明显的栈溢出 唯一的要求就是shellcode长度不能超过0x24 通过jump跳转到shellcode的位置 完整exp ...