V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yizmaoaa
V2EX  ›  Java

看到有个帖子在讨论 Java 异步 技术栈的问题... 由于今天台风不能送外卖,所以我也来分析分析..

  •  1
     
  •   yizmaoaa · 2021-07-26 16:34:34 +08:00 · 6542 次点击
    这是一个创建于 1219 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看到有个帖子讨论 Java 目前实现全链路异步的帖子

    目前全异步的技术栈大概有

    1.SpringWebFlux+Reactor+R2DBC(很久没有了解过了,不知道 Spring 还有没有支持其他服务的一些 Client)

    2.Vertx+Future/Vertx+RxJava/Vertx+Mutiny/Vertx+Coroutines

    3.Micronaut

    4.Quarkus

    Vert.x 的 Future 以及 RxJava/Mutiny/Reactor 其实这几个都差不多,基本上在异步技术栈里都是为了解决 CallBack 的问题

    主要还是 Jdk 本身的 Future 太拉稀,结果现在每家都自己搞了一套...也是挺蛋疼的

    SpringWebFlux/Micronaut/Quarkus 算是比较上层的大杂烩框架了。三家写起来其实都差不多。差别在于 Micronaut/Quarkus 主打的无反射 /云原生。总体打包镜像与内存占用都是比较小的

    目前 SpringWebFlux 与 Micronaut 都比较依赖于第三方的 Client 实现,如果第三方的 Client 实现是阻塞的,那么对于 Micronaut 与 WebFlux 来说实际上并不能提高多少吞吐的。

    对于 Quarkus 来说,由于 Quarkus 算是在 Vert.x 上面在来了一层,所以 Vert.x 自己实现的各种 Client 在 Quarkus 中也是能用的。比 Micronaut 与 WebFlux 要稍微好那么一丢丢

    不过 Micronaut 其实也能用 Vert.x 的 Client,但是效果貌似一般。主要我觉得可能还是 2 套 EventLoop 的问题,不能自上而下的用一套。

    理论上 WebFlux 也能用 Vert.x 的各种 Client,但是我觉得效果应该和 Micronaut 差不多。我也不太确定到底麻烦不麻烦。

    Micronaut 的 SqlClient 是支持 Vert.x 这边的(之前是我提交的)

    另外 Vert.x 这边基本上所有的 Client 都是自己根据协议写的,所以基本上是可以做到全链路异步的。但是碰到官方没有支持到的 Client 那么做法其实与上面的一些东西差不多了

    如果你是频次较高的去操作这些没有异步支持的 Client,那么吞吐量还是同样的不尽人意的。所以这也是在做技术选型的时候需要考虑的一点。

    如果你对性能的要求没那么高,但是希望内存占用小那么可以选择 Quarkus/Micronaut 两位都支持同步的写法。

    如果你对性能要求高,不排除异步的写法那么你可以选择 Vert.x

    不管怎么来说或者你用那个,用 Java 写异步的代码都是有点蛋疼的。

    相对来说 Vertx+Kotlin Coroutines 要舒服很多,切换到 Kt 的成本也相对的没那么大。

    另外目前我是不推荐使用 SpringWebFlux 或者 Micronaut 的异步写法的。

    在 TechempoerBenchmarks 最新一轮的性能测试中,这两位的表现并不出色

    https://www.techempower.com/benchmarks/#section=data-r20&hw=ph&test=db

    如果你用了异步这种麻烦的写法,但是实际上并没有性能的提升,这是划不来的。

    引入了异步写法的唯一目的就是希望在同样的服务器上能承受更大的吞吐。

    如果引入了异步 /提高了代码的复杂性以及可维护性并没有换回来性能的提升,这是得不偿失的。

    另外,异步所能解决的问题,同步同样能解决(只不过是加多少机器的问题...)

    第 1 条附言  ·  2021-07-27 10:35:58 +08:00
    啊~

    如果有用 Vert.x/Quarkus/Micronaut/ 招人的可以联系我 0 0 用 Java/Kotlin 都可以

    Base 上海
    52 条回复    2021-07-30 00:10:15 +08:00
    zoharSoul
        1
    zoharSoul  
       2021-07-26 16:58:55 +08:00
    说的很中肯,
    顺便补充一下, quarkus 的 native image 非常节省内存, 甚至有一个数量级的差别
    Ariver
        2
    Ariver  
       2021-07-26 17:05:12 +08:00
    感觉 java 这个推不动。
    从这几年的发展来看。
    yizmaoaa
        3
    yizmaoaa  
    OP
       2021-07-26 17:09:44 +08:00
    @Ariver 是的,我也觉得。就算 Loom 出来。到大家能接受用上都不知道是多少年后了
    tt0411
        4
    tt0411  
       2021-07-26 17:34:33 +08:00
    对中小公司来说, 全异步带来的性能提升价值没那么大, 大公司对性能敏感的服务直接原生语言了: 只能说 Java 面向的场景不是这块
    ikas
        5
    ikas  
       2021-07-26 18:34:49 +08:00
    java 异步方案现在很多.

    单说代码层面,现在缺失的是统一的规范
    虽然有类似 Promise 的 CompletableFuture,但是目前只有内置的 httpclient,jax-rs 等少量库提供这样的接口;
    也有 flow 这样内置的响应式接口,但是同样太过简单...大部分响应式也都是自己定义接口..

    即使是最新的 project-loom 提供了虚拟线程,也并未提供语言层面更简化异步代码编写的方案,或者需要其成熟以后,太遥远

    没有一个好的方便的异步语法 /统一接口,其他再多的异步库,用起来也还是蛋疼...
    x940727
        6
    x940727  
       2021-07-26 19:06:31 +08:00
    @zoharSoul 编译速度太慢了,差不多要 8G 内存,5 分钟,有点受不了……
    securityCoding
        7
    securityCoding  
       2021-07-26 19:30:12 +08:00   ❤️ 1
    老哥,你技术水平明显不低,送外卖补贴家用吗?
    yizmaoaa
        8
    yizmaoaa  
    OP
       2021-07-26 20:00:01 +08:00
    @x940727 Native-Image 的打包速度属实挺难受
    yizmaoaa
        9
    yizmaoaa  
    OP
       2021-07-26 20:00:22 +08:00
    @securityCoding 老哥客气了, 我水平属实也不高
    liuxu
        10
    liuxu  
       2021-07-26 20:13:56 +08:00   ❤️ 4
    抓哇程序员一般是美团还是饿了么,下次我点个帮我改下 bug
    yizmaoaa
        11
    yizmaoaa  
    OP
       2021-07-26 20:31:58 +08:00   ❤️ 1
    @liuxu 都跑,众包
    golangLover
        12
    golangLover  
       2021-07-26 22:33:44 +08:00 via Android
    借楼问一下,现在服务器端 api 请求远程 api 的话主要还是用 completablefuture+rest template 吗。还是有其他推荐?
    QZFCANBA
        13
    QZFCANBA  
       2021-07-26 22:48:46 +08:00
    @golangLover #12 顺便问一下,completablefuture+rest template,这套实际应用有啥坑吗?
    daimubai
        14
    daimubai  
       2021-07-26 22:52:39 +08:00
    老哥一般跑哪个时间段
    MarkLeeyun
        15
    MarkLeeyun  
       2021-07-26 23:40:27 +08:00
    老哥有空帮我改个 bug 吗?我这就点外卖。美团还是饿了么
    ljzxloaf
        16
    ljzxloaf  
       2021-07-27 08:41:48 +08:00
    老哥,跑外卖怎么入门
    Rwing
        17
    Rwing  
       2021-07-27 09:43:08 +08:00   ❤️ 1
    各位 java 大佬,何不尝试一下 c#?
    await HttpClient.GetAsync("https://www.v2ex.com")
    yizmaoaa
        18
    yizmaoaa  
    OP
       2021-07-27 09:57:45 +08:00
    @daimubai 全跑
    yizmaoaa
        19
    yizmaoaa  
    OP
       2021-07-27 09:58:05 +08:00
    @MarkLeeyun 你干的这是人事吗
    dk7952638
        20
    dk7952638  
       2021-07-27 10:02:00 +08:00
    reactor-netty 和 rsocket 怎么样,老哥有了解么
    fovecifer
        21
    fovecifer  
       2021-07-27 10:06:31 +08:00
    首先肯定要看业务类型,如果瓶颈点在数据库的话,其实同步还是异步差异不大。

    说下我自己的看法:
    1. 同步异步不是核心问题,重要是线程模型问题,像 servelet 这种一个链接一个线程的做法,虽然简单,但是性能天花板太低了
    2. 纯异步写法对开发者心智要求较高,协程的方案相对来说可接受
    3. 纯用户空间的协程也存在一定的问题(例如阻塞问题),毕竟在内核调度的时候是感知不到的
    4. 理论上最优的 N:M 的线程调度,golang 实现了这个,这也是我认同 golang 的关键点
    yizmaoaa
        22
    yizmaoaa  
    OP
       2021-07-27 10:32:34 +08:00
    @fovecifer 这个点倒是有点问题 /实际上 Servlet 很久就不是一个链接一个线程的做法了。

    第一个点纯异步写法对开发者心智要求并不高。主要还是很多开发不太理解后段的异步是怎么一个异步法。
    yizmaoaa
        23
    yizmaoaa  
    OP
       2021-07-27 10:34:07 +08:00   ❤️ 1
    @dk7952638 业务场景有限,Reactor-Netty 其实就是给 Netty 套了层 Reactor,Rsocket 没用过....
    zoharSoul
        24
    zoharSoul  
       2021-07-27 10:36:34 +08:00
    @x940727 #6 我都是 ci 的时候才编译 native image, 平时还是跑 jvm 的
    yizmaoaa
        25
    yizmaoaa  
    OP
       2021-07-27 10:44:32 +08:00
    @zoharSoul 基本上都这样...平时运行调试都是正常的走动,走 CI 的时候才打成 native
    JRay
        26
    JRay  
       2021-07-27 10:45:55 +08:00   ❤️ 1
    原来新闻里面帮忙改 bug 的外卖小哥是真的
    yizmaoaa
        27
    yizmaoaa  
    OP
       2021-07-27 10:59:10 +08:00
    @JRay 假的,送外卖一般都是在外面,不去里面的
    fovecifer
        28
    fovecifer  
       2021-07-27 11:05:09 +08:00
    @yizmaoaa 印象里 servlet 从 3.1 开始就支持 worker 线程,但是总体上好像还是一个链接一个线程

    第二个问题是我自己的切身体会,相对于协程的写法,还是复杂了一点,尤其是需要考虑背压的时候

    我再查一下 servlet 的线程模型,看看是不是我错了
    fovecifer
        29
    fovecifer  
       2021-07-27 11:07:20 +08:00
    @dk7952638 曾经用纯 netty 写过接口,当初也考虑过把 reactor 加进来,但是最后转型 OpenResty 和 golang

    个人经验,仅供参考
    INCerry
        30
    INCerry  
       2021-07-27 11:16:46 +08:00
    我觉得像 C#那样加入 async/await 就很不错,一样的协程+异步 高性能,一点点传染性无所谓了
    yizmaoaa
        31
    yizmaoaa  
    OP
       2021-07-27 11:38:41 +08:00
    @INCerry async/await 是很舒服的了
    shyling
        32
    shyling  
       2021-07-27 13:05:03 +08:00
    java,python 写异步主要是有心理负担,要考虑用的库是不是同步的,本来异步的会不会重复 wrap,这需要慢慢发展。。
    而 node.js / go 就有先天优势
    yizmaoaa
        33
    yizmaoaa  
    OP
       2021-07-27 14:10:15 +08:00
    @shyling 不太喜欢 Go 这个是主要因素
    pippoflow
        34
    pippoflow  
       2021-07-27 14:13:32 +08:00
    也不要局限于这些更高层的框架;基础的框架比如 project reactor/rxjava 这些,其实还是潜力很大的;涉及网络的比如 reactor netty 也是利器啊。我觉得异步的问题就是如果做成一个类库给客户代码用,可能会存在局限:1 )对使用方有较高的要求; 2 )如果全链路异步可能会制约一些功能的实现,或反而将问题复杂化;不过本质上,如果开发人员能力较强,还是可以驾驭的。
    sakura1
        35
    sakura1  
       2021-07-27 14:34:20 +08:00
    个人感觉异步被吹得有点神了,仔细想想只有在计算时间和等待事件的时间差距不大才有用吧
    twogoods
        36
    twogoods  
       2021-07-27 15:13:05 +08:00
    三四年前了解学习了一点这块的知识,这么多年过去了除了网关,其他普通业务场景生产上使用的依旧是少数。推不动改造学习成本太高了,堆机器不好吗
    dk7952638
        37
    dk7952638  
       2021-07-27 15:36:58 +08:00
    @fovecifer 为啥这么大的转型啊,直接语言都换了。。。
    v2orz
        38
    v2orz  
       2021-07-27 16:40:59 +08:00
    我们在生产用 webflux,感觉有点累
    可能是水平有限吧,有些问题排查复现起来很困难
    维护成本很高,容易写出问题代码
    fovecifer
        39
    fovecifer  
       2021-07-27 16:45:26 +08:00
    @dk7952638 主要考虑开发效率和资源占用,在当时的应用场景下,OpenResty 和 golang 开发出来的接口性能会高很多
    jjianwen68
        40
    jjianwen68  
       2021-07-27 17:03:27 +08:00
    问个问题,传统方法,一般会加个 j2cache 做两级缓存;换用 webflux,你们一般还做两级缓存吗
    yizmaoaa
        41
    yizmaoaa  
    OP
       2021-07-27 17:14:11 +08:00
    @pippoflow 在 Java 里异步要解决的问题本身就应该是一些业务简单高频 IO 的程序
    yizmaoaa
        42
    yizmaoaa  
    OP
       2021-07-27 17:15:13 +08:00
    @sakura1 没人吹这个,这个玩意没啥好吹的,实际上就是在高 IO 的场景下可以考虑的玩意
    yizmaoaa
        43
    yizmaoaa  
    OP
       2021-07-27 17:16:23 +08:00
    @twogoods 一般在业务在 Java 里用这些属实有点找虐.
    yizmaoaa
        44
    yizmaoaa  
    OP
       2021-07-27 17:17:40 +08:00
    @v2orz 累就对了,不然这么多年了,Java 的异步还是少规模使用的。很多宁愿去用 Go 写也不愿意使用 Java 的异步库。
    很难顶
    chenshun00
        45
    chenshun00  
       2021-07-27 17:20:22 +08:00
    都在讨论技术问题,我歪一下楼,异步技术现在是什么情况尚且不讨论。
    还是需要考虑以下几个问题
    1 、团队技术是不是 hold 住。目前大部分从业人员水平参差不齐。
    2 、后续的维护以及问题排除的难度相比现在是降低了还是提高了。
    3 、招人,团队流动性会不会导致难搞到人。
    4 、如果一开始不是异步,改造异步的推广谁来搞。万一出了问题一线同志肯定背不起,估计只能从管理层来背。
    yizmaoaa
        46
    yizmaoaa  
    OP
       2021-07-27 18:27:13 +08:00
    @chenshun00 所以说大部分情况都不太推荐大规模使用..... 能 Hold 住的人属实不多。其实问题排查倒是没那么难
    myCupOfTea
        47
    myCupOfTea  
       2021-07-28 14:06:47 +08:00
    话说 webflux 是不是要使用异步的连接客户端
    但是我一搜 webflux 相关的资料,都是使用的旧的 sprint-data-redis 这种同步客户端啊
    bthulu
        48
    bthulu  
       2021-07-28 15:02:05 +08:00
    java 不异步, 异步非 java
    yizmaoaa
        49
    yizmaoaa  
    OP
       2021-07-28 23:11:03 +08:00
    @myCupOfTea 我没使用过 WebFlux,如果 Spring-data-redis 下面使用的是 lettuce 的话那么下面可能是 Reactor 的,如果是 Jedis 的话那肯定还是同步的逻辑
    yizmaoaa
        50
    yizmaoaa  
    OP
       2021-07-28 23:13:23 +08:00
    @bthulu 好像说的有那么点道理 /
    swim2sun
        51
    swim2sun  
       2021-07-29 12:11:05 +08:00 via iPhone
    说下我的理解吧,其实你们所谈论的“异步”基本上是指“同步非阻塞 IO 模型+异步编程模型”,真正要全异步的话可能要用上 AIO 才算彻底的异步,目前 java 平台貌似没有这样的成熟框架。
    这些异步框架本质上是通过资源的合理调度提高吞吐量的,这里指的资源大部分是指线程
    yizmaoaa
        52
    yizmaoaa  
    OP
       2021-07-30 00:10:15 +08:00
    @swim2sun 这样说其实也差不多,但是彻底的 AIO 异步也并没有比现在的模式强很多。目前 Java 的这些异步框架本质上确实是合理的对资源进行调度提高对吞吐量
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5485 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:34 · PVG 16:34 · LAX 00:34 · JFK 03:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.