• 张申傲
    2023-01-30 来自北京
    个人认为,理解异步化有个前提,就是要区分两个线程:请求处理主线程&业务异步子线程: - 请求处理主线程:由 Dubbo 框架提供,主要用于接收 RPC 请求。线程池大小默认为200。 - 业务异步子线程:由业务自定义,可设置线程池大小、队列长度、拒绝策略等,用于异步执行业务逻辑。 异步化的核心思想在于,将本来需要由主线程来执行的耗时操作,交给异步子线程来执行,使得主线程可以快速执行完成,避免 Dubbo 线程池被耗尽导致服务不可用。站在调用方的角度来看,实际请求的执行时间并没有缩短,但是服务整体的吞吐量是有很大的提升的。

    作者回复: 你好,张申傲:非常 nice,你总结的非常到位,很有自己独到的见解,点赞~

    共 2 条评论
    13
  • Six Days
    2023-03-16 来自广东
    请问一下asyncContext.write(resultInfo); 这里将resultInfo 写入Future 之后,Dubbo框架什么时候调用Future.get 获取计算结果?

    作者回复: 你好,Six Days:【asyncContext.write(resultInfo); 】执行之后是将结果写入到了 Future 当中,但是还有另外一个底层在调用这个 Future#get 的结果,这个调用的地方就是在【org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleRequest】方法中的【handler.reply(channel, msg);】代码处,【handler.reply(channel, msg);】返回的对象就是 Future 对象,然后调用 Future 对象的 whenComplete 方法,调用完后若没有结果就会等待,有结果的话就会立马进入 whenComplete 方法的回调逻辑中。

    
    2
  • 咸鱼王
    2023-03-10 来自江西
    之前只用过在reference标签上设置async="true" sent="false"的方式来实现无返回值的异步,这种应该是属于消费端的异步吧? 没想到还支持将provider的dubbo线程和业务处理线程分开,释放dubbo线程,还可以返回结果,开了眼了。

    作者回复: 你好,在雨中:【async="true" sent="false"】结合起来就是异步形式,发送请求时并不会等待消息发送出去,而是将消费放入到队列中就完事了。至于后续要在消费方拿到结果的话,可以想办法从 RpcContext 中拿到 Future 对象并调用 Future#get 方法拿到返回值。

    
    2
  • 张洋
    2023-01-03 来自广东
    老师,看了下这块的源码,其实dubbo还是通过ThreadLocal(InternalThreadLocal可以在父子线程中共享数据)来存储context,ATTACHMENT 这些属性,感觉还是通过ThreadLocal的方案,不过是dubbo自己做了一层封装吧,不知道这样理解对不

    作者回复: 你好,张洋:你理解的没错,dubbo 在衔接上下文的时候,本质还是进行了 ThreadLocal 传递。

    
    2
  • java小霸王
    2022-12-27 来自广东
    拦截处只需要调用 java.util.concurrent.CompletableFuture#get(long timeout, TimeUnit unit) 方法就可以很轻松地拿到异步化结果了。 这里拦截处是谁去调用呀,另外的线程轮训吗,还是一开始请求的线程阻塞。

    作者回复: 你好,java小霸王:这里为了简单理解,我抽象为了拦截处。等你学到后面的“发布、订阅、调用”章节的时候,掌握的知识点更多的时候,你通过断点的时候,你会发现 org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleRequest 方法的 Future 对象在 whenComplete 方法中持有了 channel(即最终是 NettyClient)的引用。

    共 3 条评论
    2
  • SunshineBoy
    2022-12-30 来自广东
    老师,举例时可以把各种IO模型处理方式的弊端加上吗?毕竟内存是有限的

    作者回复: 你好,SunshineBoy:不好意思,主要是每篇篇幅有限,我给你找了一篇写的有点生活形象点的例子,附上链接如下: https://blog.csdn.net/lqy971966/article/details/118157808?spm=1001.2101.3001.6650.9&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-9-118157808-blog-100849453.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-9-118157808-blog-100849453.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=10

    
    1
  • Geek_1cc6d1
    2022-12-30 来自广东
    provider异步的意义是啥?避免dubbo线程耗尽么,直接把dubbo线程数量搞大点不就行了?

    作者回复: 你好,Geek_1cc6d1:这个问题在前面的问题回答过,我直接将内容引用过来了: 其次可以这么理解,提供方的异步化旨在提高吞吐量,说白了就是用自己的线程池去承处理业务,以此来释放Dubbo框架本身的线程去处理其他耗时比较短的请求,就有点类似于脏活累活交给一个特定的线程池让它自己扛,能扛多少是多少,既轻松又快的活Dubbo自己干,见缝插针似的尽可能提升提供方的整个吞吐。 最后如果是这种慢请求打到单机瓶颈了那还真得好好看看优化,如果是那种耗时非常短的请求打到单机瓶颈了,那你得后续考虑加大Dubbo本身线程核心数据或扩容或者有损限流降级等等之类的了。

    
    1
  • 胡月🌈
    2022-12-22 来自湖南
    改造后,拦截地方feature.get也会阻塞住,消耗线程资源吧。这样岂不是每个拦截的地方消耗的线程资源并没有减少。大量请求过来的时候,线程还是不够用。

    作者回复: 你好,胡月:得先感谢你的认真思考,提出了个比较好的问题。 其次可以这么理解,提供方的异步化旨在提高吞吐量,说白了就是用自己的线程池去承处理业务,以此来释放Dubbo框架本身的线程去处理其他耗时比较短的请求,就有点类似于脏活累活交给一个特定的线程池让它自己扛,能扛多少是多少,既轻松又快的活Dubbo自己干,见缝插针似的尽可能提升提供方的整个吞吐。 最后如果是这种慢请求打到单机瓶颈了那还真得好好看看优化,如果是那种耗时非常短的请求打到单机瓶颈了,那你得后续考虑加大Dubbo本身线程核心数据或扩容或者有损限流降级等等之类的了。

    共 7 条评论
    1
  • 就是那个刘涛
    2023-08-29 来自河南
    请教老师一个问题: 异步操作的时候,业务子线程没有执行完毕之前,dubbo主线程是不是暂停等待子线程的结果呢?如果实在这样的话,主线程不还是被占用着吗?

    作者回复: 你好,举个简单的例子:你通过 nio 写一个主线程接收,子线程处理并 write 响应,你可以看看,主线程是不是在等待子线程。 你把通信收发想象为400米接力赛,接力棒比喻为通信句柄,只要拿着接力棒就能说话,就能写数据,写完扔了释放就完事了。

    
    
  • 驽马一二三四五六七八...
    2023-08-02 来自福建
    老师,请问一下,在HeaderExchangeHandler#handleRequest中为future设置了一个异步回调方法,当线程异步执行完成后,是Dubbo的内部线程去执行这个异步回调方法么?与Dubbo处理请求的线程是属于同一个线程池的么?

    作者回复: 你好,驽马一二三四五六七:感知到消息进来的是 netty 线程池,处理业务逻辑的,可以是 dubbo 业务线程池,也可以是 netty 自带的线程池。至于你说的问题,需要考虑使用的是什么Dispatcher类型。

    
    