Java 目前实现全异步的方式有哪些 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ljzxloaf
V2EX    Java

Java 目前实现全异步的方式有哪些

  •  
  •   ljzxloaf 2021-07-25 10:20:35 +08:00 8566 次点击
    这是一个创建于 1586 天前的主题,其中的信息可能已经有所发展或是发生改变。

    除了 callback

    第 1 条附言    2021-07-25 11:24:16 +08:00
    自己生产实践过的,传说中的技术就算了
    第 2 条附言    2021-07-25 11:28:40 +08:00
    callback 会割裂业务逻辑,代码也不好看。协程还遥遥无期。想知道有没有真的很好地实现了全异步的系统。可读性、开发效率、debug 等周边支持都很不错的那种
    第 3 条附言    2021-07-25 11:35:22 +08:00
    现在估计很多服务还是跑在 tomcat 上的,tomcat 上想要异步必须得使用异步 servlet,但是感觉这玩意儿也没几个人用。java 异步太难了
    第 4 条附言    2021-07-25 13:35:43 +08:00
    似乎 webflux 可以一站?
    第 5 条附言    2021-07-25 13:53:14 +08:00
    哈哈,觉得这位兄台说得很有道理
    t/664892?p=1#r_10031078
    第 6 条附言    2021-07-25 17:06:48 +08:00

    第 7 条附言    2021-07-25 17:08:06 +08:00
    加了个投票,诸君可以为自己所用的技术栈投个票,应该是支持多选的(别重复投啊)
    第 8 条附言    2021-07-25 17:15:38 +08:00
    选项设置得不好,servlet stack 算是其他吧,不是下面这几种的都是 servlet stack,简单来说,就是不用学新技术的。虽然有可能也是异步,比如用 netty 自己实现的异步 server,但是写起来还是 future/callback 这种喜闻乐见的东西。
    第 9 条附言    2021-07-25 18:51:56 +08:00
    比例不对吧。。webflux/vertx/rx 使用率这么高的吗。。没用这些的兄弟们把 servlet 顶上来
    第 10 条附言    2021-07-26 06:14:16 +08:00
    有些同学认为后端的瓶颈在于 db,确实 db 一般来说比较脆弱,没有很好的管理的话扩展性比较差。但是无论我们用的是异步还是同步,对 db 的总请求不变啊。用异步更多还是减少资源耗费,降低成本吧。

    所以我觉得 t/664892?p=1#r_10031078 这位兄台说得很有道理,如果服务 qps 没那么高,提高性能就不能节约多少成本,相反如果开发效率、服务质量、后期维护等受到了影响,就有点得不偿失。

    不过这题我们先假设有巨量 qps,否则讨论也没啥意义了
    48 条回复    2021-07-27 09:28:02 +08:00
    ikas
        1
    ikas  
       2021-07-25 10:44:27 +08:00
    1.各种基于 Reactor 模型的框架 /库
    2.内置的 java.util.concurrent.CompletableFuture/或者使用其的框架 /库
    passerbytiny
        2
    passerbytiny  
       2021-07-25 10:57:48 +08:00 via Android
    Java 本体的是 Task/Executor/Future 框架,基于线程池,可满足全部异步编程模型,但是编码易用性几乎为零。

    三方框架大多都有编码友好的异步编程组件,通常都是基于 Java 本体的那个框架。如果你用 Spring,那么 @Async 就是用来做异步编程的,编码很容易,但是不支持全部异步编程模型。 @Async 的异步方法只能再抛出事件,不能返回 Futute,或者说仅支持 callback 模式,不支持 await 模式。
    zm8m93Q1e5otOC69     3
    zm8m93Q1e5otOC69  
       2021-07-25 11:07:20 +08:00 via Android
    Vert.x
    xuqd
        4
    xuqd  
       2021-07-25 11:16:34 +08:00
    JDBC 会比较麻烦,别的还好
    golangLover
        5
    golangLover  
       2021-07-25 11:17:25 +08:00 via Android
    @passerbytiny 为什么说编码易用性为 0,completablefuture 不好用吗?
    passerbytiny
        6
    passerbytiny  
       2021-07-25 11:32:35 +08:00 via Android
    @golangLover 你得手写代码配置执行器 /线程池。此外可以对比下其他语言的异步语法。
    sagaxu
        7
    sagaxu  
       2021-07-25 11:40:01 +08:00 via Android   1
    JVM 生态上 vertx + kotlin coroutines,丝般顺滑
    ljzxloaf
        8
    ljzxloaf  
    OP
       2021-07-25 11:41:12 +08:00
    @passerbytiny #2 web 应用哪里用得着 @Async,都是基于 nio 包装个异步接口调用,@Async 本质是线程池,用这个处理 io 肯定是不行的
    ljzxloaf
        9
    ljzxloaf  
    OP
       2021-07-25 11:43:32 +08:00
    @sagaxu #7 求实战经验,这俩学习成本都不低啊
    passerbytiny
        10
    passerbytiny  
       2021-07-25 11:47:25 +08:00 via Android
    @ljzxloaf 你家 Web 应用该不是只有 Web 入口跟 SQL 两层吧。此外,IO 异步跟异步编程是两码事。
    1194129822
        11
    1194129822  
       2021-07-25 11:53:59 +08:00
    异步?简单的事情更简单,复杂的事情更复杂,而且总有一个链路要处理背压,如果无数请求都直接传给数据库,系统还有什么稳定性可言。只要涉及到 jdbc,现在 java 中异步也就是个玩具罢了。unix 的哲学就是同步比异步好。全链路异步,不用 jdbc,使用 redis, mogodb 之类(也是 epoll 模拟),只有 win 有 iocp, 而且异步的压力最终也会到 os 和 db 上。
    spring 的 reactor,你去看看呗。也就几百个运算符。
    ipwx
        12
    ipwx  
       2021-07-25 12:09:33 +08:00
    Actor model 很好用的。不过我不太熟 java,jvm 上只知道一个 akka 。
    ljzxloaf
        13
    ljzxloaf  
    OP
       2021-07-25 12:11:05 +08:00
    @passerbytiny #10 web 应用不就这两层吗,就是收发数据啊,中间的 get/set 难道还需要分成几个任务去跑?这就没必要了吧?
    ikas
        14
    ikas  
       2021-07-25 12:25:19 +08:00   2
    哈哈,笑死了..什么是传说中的技术..所谓的难其实就是想要 await 与 async 么
    rb6221
        15
    rb6221  
       2021-07-25 12:28:36 +08:00   1
    看看第三方的协程库吧,纯 java 实现,我记得有一些
    ljzxloaf
        16
    ljzxloaf  
    OP
       2021-07-25 12:45:57 +08:00
    @ikas #14 有啥好笑的。。如果要传说中的技术我谷歌搜下就完事了,就是想知道生产实践中是什么情况。比如什么 ddd 、servicemesh 这些,对我来说就是传说中的技术,因为没在实践中看到过。传说中的技术就是没有生产实践过的技术
    Jooooooooo
        17
    Jooooooooo  
       2021-07-25 13:06:33 +08:00
    CompletableFuture 已经很好用啦

    什么 A, B 都做完再做 C 用这写起来已经够便捷了
    ccde8259
        18
    ccde8259  
       2021-07-25 13:44:18 +08:00 via iPhone
    目前生产实践用的是线程池挂 Job,然后 CountDownLatch 回来,可惜不按代码行数发工资。
    进一步就是用 JUC 下的 CF,但是写起来还是有点难受,因为需要把大量同步代码封装成返回 CF 的调用。
    再进一步就是 Vert.x 的 Future,版本到 4.0 几乎所有 API 都支持 Future 返回。then 等链式调用对于 Callback Hell 有所缓解。
    妥协之选就是 Quarkus 。Route Layer 往下都是 Vert.x 实现,往上则是 RESTEasy 的 JAX-RS 实现。IO Thread 跟 Work Thread 分开,实现 IO 异步业务同步。
    Project Loom 都不知道延期了多久,能不能赶得上 JDK17 这个 LTS……毕竟最终目标是写同步代码用异步执行。
    sagaxu
        19
    sagaxu  
       2021-07-25 13:48:29 +08:00 via Android
    @ljzxloaf 学习成本也还好,vertx 就是 jvm 版的 nodejs,用起来姿势差不多。kotlin coroutine 花一天了解一下 suspend 和 dispatcher,正常使用没问题了。两者的粘合,vertx 官方有专门的支持,vertx 4.0 之后基本是无缝的了。但跟 spring 粘合使用的时候,就有点儿脏了,spring 注入的是单例,而 vertx 讲究的是不要跨 context,一般同 verticle 内办事,跨 verticle 得走 rpc 。
    VHacker1989
        20
    VHacker1989  
       2021-07-25 13:49:56 +08:00
    reactor 和 rxjava 都实现了 reactivex,rxjava 兼容性好,能在 Android 上跑,但后端生态肯定 reactor 好,从数据库层的 r2dbc,web 层 webflux,不少 rpc,消息队列,http client 都支持 reactor,真正的全链路响应式
    sagaxu
        21
    sagaxu  
       2021-07-25 13:50:33 +08:00 via Android
    @ccde8259 loom 稳定版不太可能赶得上 17 了,下一个 lts 应该问题不大,下一个 lts 还能期待一下满血版的 zgc
    ljzxloaf
        22
    ljzxloaf  
    OP
       2021-07-25 13:55:47 +08:00
    @ccde8259 #18 理想丰满,现实骨感
    ccde8259
        23
    ccde8259  
       2021-07-25 14:02:41 +08:00 via iPhone   1
    @sagaxu 再等下一个 LTS 怕是已经开滴滴送外卖去了……人生能有几个 LTS ?
    zoharSoul
        24
    zoharSoul  
       2021-07-25 14:57:11 +08:00   1
    Vert.x + kotlin
    wqhui
        25
    wqhui  
       2021-07-25 17:26:33 +08:00
    用 webflux 写过一个主要耗时是 io 的服务,webflux 这套东西很少看到有人用,目前只有 no sql 的数据库支持异步,比如 mongodb 、redis,传统的 mysql 不行,写复杂业务很恶心,而且懂这套的人太少了,意味着二次开发及维护困难,一般就网关用用,属于小众的大杀器
    ljzxloaf
        26
    ljzxloaf  
    OP
       2021-07-25 17:32:25 +08:00
    @wqhui #25 这么看也挺适合那种 BFF ( Backend for Frontend )聚合服务的,调接口组装数据再返给前端
    Magentaize
        27
    Magentaize  
       2021-07-25 20:24:55 +08:00
    说实话在 await 和 reactivex 里选 reactivex 使用体验更好,和同步方法的交互也更舒适,callback 肯定是能不用就不用
    golangLover
        28
    golangLover  
       2021-07-25 20:25:46 +08:00 via Android
    看了一圈,结论是没有好的解决方案。唯有换 kotlin 。我知道 ea 发明了个 ea-async 但 ea 已经一两年没有维护了。
    yazinnnn
        29
    yazinnnn  
       2021-07-25 20:42:34 +08:00
    Mutiny
    reactor
    rxjava
    vertx

    目前 java 的常用的 reactive 库就有这几个吧,都跟 kotlin 的 coroutine 有不错的互动
    iseki
        30
    iseki  
       2021-07-25 21:42:45 +08:00
    vertx + kotlin coroutine,爽(
    golangLover
        31
    golangLover  
       2021-07-25 21:49:29 +08:00 via Android
    @Magentaize rxjava 就没见过在服务器端用的,基本上看到的都是在安卓用
    pigspy
        32
    pigspy  
       2021-07-25 22:01:12 +08:00
    我们以前写 mqtt 服务器就是 vertx,用到了 kotlin,不过没用协程,写起来挺方便的啊
    vertx 提供了很多异步风格的 client,我们当时就用到了 redis 和 hazelcast
    fewok
        33
    fewok  
       2021-07-25 22:07:50 +08:00
    累不累,直接上 golang 不好么?
    oldmanong
        34
    oldmanong  
       2021-07-25 22:14:51 +08:00 via iPhone   1
    在以前的公司用 rxjava 把所有服务端改为了异步,技术性大于实用性,有一些坑需要注意。后端主要的瓶颈还是数据库,没见过单纯因为线程数不足而影响服务的情况
    qiyuey
        35
    qiyuey  
       2021-07-25 23:21:30 +08:00
    阿里的 wisp2 可以
    micean
        36
    micean  
       2021-07-25 23:27:33 +08:00
    投票里的 vertx stack 和 kt coroutine 应该算是同一个吧。。。大部分用 vertx 都转 kt 加持了
    Feiex
        37
    Feiex  
       2021-07-26 00:14:35 +08:00
    推荐 ParSeq,一个 java 异步化工具。

    生产环境大规模实践过。
    sagaxu
        38
    sagaxu  
       2021-07-26 00:36:23 +08:00 via Android
    @micean vertx 和 kt 不能算同一个,kt 也有用 ktor 的
    iseki
        39
    iseki  
       2021-07-26 02:59:43 +08:00 via Android
    毕竟纯 vertx 写起来挺难受的
    dreamramon
        40
    dreamramon  
       2021-07-26 05:13:17 +08:00
    用 vertx 6 年了,很方便啊。
    ljzxloaf
        41
    ljzxloaf  
    OP
       2021-07-26 06:46:06 +08:00
    不能 append 了。。

    简单总结下:看起来这几种异步实践流行度差不多,所以如果没有 reactive 经验的直接上 vertx+kt coroutine ;有 reactive 经验:如果当前还是 servlet,直接上 webflux ;如果已经是异步 server,可以上 webflux 也可以上 rxjava ;懒得折腾的继续用 future/callback 吧,等 java 发布 coroutine 。

    当然还有个不错的选择:转 golang 吧
    ljzxloaf
        42
    ljzxloaf  
    OP
       2021-07-26 06:49:41 +08:00
    @ljzxloaf #41 异步 server 应该上不了 webflux 了,webflux 包括了 server
    BBCCBB
        43
    BBCCBB  
       2021-07-26 08:45:54 +08:00
    @wqhui sql 有 r2dbc 规范, 很多数据库都支持貌似.
    p1gd0g
        44
    p1gd0g  
       2021-07-26 09:44:44 +08:00
    我发现 v2 黑夜模式看不到投票的选项。
    DonaldY
        45
    DonaldY  
       2021-07-26 15:53:27 +08:00
    全异步就得解决数据库连接的问题。例如 JDBC,阻塞转换为非阻塞才行。

    否则,都相差不多。
    cloudopt
        46
    cloudopt  
       2021-07-26 17:04:46 +08:00
    试试看 Cloudopt Next 吧:

    https://github.com/cloudoptlab/cloudopt-next

    Cloudopt Next 是一个非常轻量级且现代的、基于 Kotlin 编写的全栈开发框架,同时支持 Java 和 Kotlin,您可以处理 Url 的解析,数据的装,Json 的输出等等,从根本上减少开发时间、提升开发体验。

    [Cloudopt Next]( https://next.cloudopt.net/) 是一个非常轻量级且现代的、基于 Kotlin 编写的全栈开发框架,同时支持 Java 和 Kotlin,您可以处理 Url 的解析,数据的封装,Json 的输出等等,从根本上减少开发时间、提升开发体验。


    ** Cloudopt Next 主要拥有以下特点:**


    > **简单** 极简设计,几乎不要任何配置,不依赖 Tomcat 、Jetty 等 Web 容器。



    > **异步** 基于 vertx 轻松实现高性能的异步服务。



    > **扩展** 支持 vertx 体系的各种组件,同时支持通过插件扩展功能,官方也提供了大量好用的插件。



    > **中文** 全中文文档、中文社区,帮助中文开发者快速上手。



    **GitHub:**


    https://github.com/cloudoptlab/cloudopt-next


    **开源中国:**

    https://gitee.com/cloudopt/cloudopt-next


    ## 示例


    您可以通过访问[Cloudopt Next 的官网]( https://next.cloudopt.net)来查看文档,也可以前往[Example]( https://github.com/cloudoptlab/cloudopt-next-example)查看简单的示例。


    ### 路由


    让我们来看看一个简单的基于 Cloudopt Next 的路由:


    ```kotlin
    @API("/")
    class IndexController : Resource() {
    @GET
    fun get(){
    renderHtml(view = "index")
    }
    }
    ```


    ```java
    @API(value = "/")
    public class IndexController extends Resource {

    @GET
    public void get(){
    View v = new View();
    v.setView("index");
    renderHtml(v);
    }
    }
    ```


    ### 启动


    ```kotlin
    fun main(args: Array<String>) {
    NextServer.run()
    }
    ```


    ```java
    public static void main(String args[]) {
    NextServer.run();
    }
    ```


    ### 超好用的协程
    ```kotlin
    var value = await<String>{handler->
    handler.complete(RedisManager.sync().get("key"))
    }
    ```
    ###
    ### WebSocket
    ```kotlin
    @WebSocket("/websocket")
    class WebSocketHandler : WebSocketResource {

    override suspend fun onConnectionSuccess(websocket: ServerWebSocket) {
    websocket.writeTextMessage("Connection successful!") {
    println("The event of after write.")
    }

    val buffer: Buffer = Buffer.buffer().appendInt(123).appendFloat(1.23f)

    websocket.writeBinaryMessage(buffer) {
    println("The event of after write binary.")
    }
    }

    override suspend fun onConnectionFailure(throwable: Throwable) {

    }

    override suspend fun onConnectionComplete(websocket: ServerWebSocket) {

    }

    override suspend fun onFrameMessage(frame: WebSocketFrame, websocket: ServerWebSocket) {

    }

    override suspend fun onTextMessage(message: String, websocket: ServerWebSocket) {
    println(message)
    websocket.writeTextMessage("This is the message from the server!")
    }

    override suspend fun onBinaryMessage(buffer: Buffer, websocket: ServerWebSocket) {

    }

    override suspend fun onPong(buffer: Buffer, websocket: ServerWebSocket) {

    }

    override suspend fun onException(throwable: Throwable, websocket: ServerWebSocket) {
    throwable.printStackTrace()
    if (!websocket.isClosed) {
    websocket.close()
    }
    }

    override suspend fun onDrain(websocket: ServerWebSocket) {

    }

    override suspend fun onEnd(websocket: ServerWebSocket) {
    println("Connection was closed.")
    }
    }
    ```
    ### SockJS


    ```kotlin
    @SocketJS("/socket/api/*")
    class SocketController : SocketJSResource {
    override fun handler(userSocketConnection: SockJSSocket) {
    println(userSocketConnection)
    userSocketConnection.handler {message->
    println(message)
    userSocketConnection.write("Hello world!")
    }
    }
    }
    ```


    ### 插件


    ```kotlin
    fun main(args: Array<String>) {
    NextServer.addPlugin(TestPlugin())
    NextServer.addPlugin(EventPlugin())
    NextServer.run()
    }
    ```
    cloudopt
        47
    cloudopt  
       2021-07-26 17:06:05 +08:00
    尴尬了,回复不支持 markdown,大家可以去 GitHub 看看。
    chocotan
        48
    chocotan  
       2021-07-27 09:28:02 +08:00
    我们的 api 网关是异步 servlet
    部分模块也有用 rxjava
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     906 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 20:27 PVG 04:27 LAX 12:27 JFK 15:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86