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

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

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

    除了 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
    哈哈,觉得这位兄台说得很有道理
    https://www.v2ex.com/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 的总请求不变啊。用异步更多还是减少资源耗费,降低成本吧。

    所以我觉得 https://www.v2ex.com/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 模式。
    uselessVisitor
        3
    uselessVisitor  
       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 么
    janus77
        15
    janus77  
       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   ·   实用小工具   ·   1810 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 16:40 · PVG 00:40 · LAX 08:40 · JFK 11:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.