首页 > 其他分享 >【DUBBO】dubbo超时处理机制浅析

【DUBBO】dubbo超时处理机制浅析

时间:2024-11-04 20:46:22浏览次数:3  
标签:DUBBO 调用 dubbo 接口 设置 超时 浅析 服务端 客户端

在RPC调用过程中,由于网络或服务端等不可靠,我们常常会收到Timeout异常。这是因为RPC框架为避免长时间等待导致客户端资源(线程)耗尽,都会提供设置超时时间的属性。
在Dubbo中,使用timeout 这个属性来给某个服务调用设置超时间(默认1s),如果服务在设置的超时时间内未返回结果,则会抛出超时异常:TimeoutException。
接下来我们来看看,dubbo的超时机制

Dubbo架构图与调用链

相信架构图和调用链大家看见过N次了,简单介绍一下每个分层的作用

架构图

在这里插入图片描述

  • Config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
  • Proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory
  • Registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService
  • Cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance
  • Monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService
  • Protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter
  • Exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • Transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec
  • Serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool

其中,较为核心的层有:
Config 配置层、Proxy 服务代理层、Registry 注册中心层、Cluster 路由层、Protocol 远程调用层

调用链

在这里插入图片描述

超时设置方式


Dubbo的属性支持全局配置,方法级别,接口级别的配置(以XML为例)。
方法级设置

<!-- 提供方 -->
<dubbo:service interface="x.DemoService" ref="demoServiceImpl">
    <dubbo:method name="test" timeout="10000"/>
</dubbo:service>
<!-- 消费方 -->
<dubbo:reference interface="x.DemoService" id="demoService" version="1.0">
    <dubbo:method name="test" timeout="10000"/>
</dubbo:reference>

接口级设置

<!-- 提供方 -->
<dubbo:service interface="x.DemoService" ref="demoServiceImpl" timeout="10000"/>
<!-- 消费方 -->
<dubbo:reference interface="x.DemoService" id="demoService" version="1.0" timeout="10000"/>

全局级设置

<!--提供方-->
<dubbo:provider timeout="10000"/>
<!--消费方-->
<dubbo:consumer timeout="10000"/>

优先级


原则如下,使用的优先于提供的,局部的优先于全局的。
故优先级:
自定义超时时间的优先级最高
服务消费者 的优先级要高于 服务提供者
方法配置 的优先级要高于 接口配置接口配置 的优先级要高于 全局配置

处理机制


消费端处理超时

首先我们先来看下消费端调用链路,一次请求经过路由选择,负载均衡,Filter处理,最终到DubboInvoker 处理,如下图所示:

proxy Cluster层的Invoker Filter Protocol的Invoker

我们就从Protocol层的Invoker方法分析:
在这里插入图片描述
我们此次分析的是dubbo协议的调用,对超时处理的逻辑就在DubboInvoker的doInvoke方法中,代码如下:

  1. 计算超时时间, 然后向服务端发起请求,并返回future作为结果
    在这里插入图片描述
    计算Timeout时,只需读取方法上的参数即可,因为在初始化时,已经把优先级的顺序执行完成了。可能有人有疑问:context.getObjectAttachment(TIMEOUT_KEY),这行代码并没有传methodName,那是因为RPCContext是RPC调用的上下文,允许我们自定义动态设置超时时间,所以自定义设置的超时时间比方法的优先级更高。
    这里要注意RpcContext 在读服务调用过程中存在串组的问题,这种方案慎用,具体参考使用Dubbo的RpcContext居然那么多坑
    在这里插入图片描述
    在这里插入图片描述

  2. client客户端发起请求时,内部会构造一个DefaultFuture, 然后创建一个超时检查任务TimeoutCheckTask,交由HashedWheelTimer来检查超时情况。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    超时则调用HashedWheelTimeout类中的expire方法
    在这里插入图片描述

  3. 检测超时之后,包装Response 通过判断请求是否发送,来确认是消费端超时还是服务端超时。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

以上我们可以看出,判断是客户端超时还是服务端超时,是通过是否将消息发送出去为准的。实际上这并不能区分出到底是客户端还是服务端卡住了。当客户端自己慢的时候,它很可能认为是服务端超时了。

消费端超时情况分析与解决方案

可能的原因
  1. 服务端压力大,客户端过来的请求远远超过服务端处理的能力,导致许多请求无法在指定的时间返回结果,客户端自动返回一个超时的异常响应来结束此次调用。
  2. 客户端 Load 很高,负载压力很大的时候,会因为客户端请求发不出去、响应卡在 TCP Buffer 等问题,造成超时。因为客户端接收到服务端发来的数据或者请求服务端的数据,都会在系统层面排队,如果系统负载比较高,在内核态的时间占比就会加长,从而造成客户端获取到值时已经超时。
  3. 通常是业务处理太慢,可在服务提供方机器上执行:jstack [PID] > jstack.log 分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请调高 timeout 阈值。
  4. GC问题,检查服务端或客户端频繁GC的原因,可通过优化JVM参数,增加资源等方式解决GC问题。
  5. 网络问题;
排查工具
  1. 借助链路跟踪的分析服务(比如阿里的 ARMS)来分析下各个点的耗时情况。

服务端处理超时

server一般不处理超时。仅在Invocation中设置了TIMEOUT_ATTACHENT_KEY属性时,才会获取Timeout值,并把超时时间设置到RpcContext上下文中,以供后续TimeoutFilter使用。

long timeout = RpcUtils.getTimeout(invocation, -1);
if (timeout != -1) {
    context.set(TIME_COUNTDOWN_KEY,TimeoutCountDown.newCountDown(timeout, TimeUnit.MILLISECONDS));
}
// TIMEOUT_ATTACHENT_KEY = "_TO"
public static long getTimeout(Invocation invocation, long defaultTimeout) {
    long timeout = defaultTimeout;
    Object genericTimeout = invocation.getObjectAttachment(TIMEOUT_ATTACHENT_KEY);
    if (genericTimeout != null) {
        timeout = convertToNumber(genericTimeout, defaultTimeout);
    }
    return timeout;
}

在TimeoutFilter中检测超时,会将结果清空,且仅打了行warn日志,这也在侧边体现了,其实服务端的超时并不是特别重要。
在这里插入图片描述
服务端超时有个问题,当真的设置了超时时间,仅仅只是把结果清空了,那超时后,客户端拿到的结果也只是个空结果,但客户端并不知道是真的超时返回的空,还是数据获取到为空,且清空结果这个动作本身也挺危险的。
还有就是,服务端就算不超时,但还有网络传输时间,客户端处理时间等操作,只是设置服务端超时时间,还是不能保证服务的稳定性,所以这里还是有些问题的。

服务端端超时情况分析与解决方案

可能的原因

  1. 服务端逻辑处理相对耗时。
  2. 服务端负载请求过高,无法响应。
  3. 当前的超时参数设置阈值与现实情况相差较大。

排查和解决步骤

  1. 根据接口名称查看是否存在耗时处理情况。
  2. 可监控服务器状态,及服务端调用的服务调用情况。
  3. 尝试将超时参数调大一些,或者不设置超时时间。

动态调整超时设置


在某些情况下, 你可能有调整调用超时设置情况,但是又不想改代码发布应用。这里可以通过以下几种方式实现:
11. Dubbo Admin 设置
Dubbo 提供动态调整服务超时时间的能力,在无需重启应用的情况下调整服务的超时时间,这对于临时解决一些服务上下游依赖不稳定而导致的调用失败问题非常有效。
这里可以参见官方文档 动态调整服务超时时间
12. 增加额外的线程池
简单一点可以在Filter 中使用线程池来处理请求,通过submit 方法,通过配置中心的不同级别的超时配置,使用futrue.get(timeout) 方法来实现超时控制,这里需要你在dubbo 服务级别设置的超时时间要比 配置中心的值要大。

总结


我们从源码的角度上介绍了Dubbo的超时处理机制,感兴趣可以自己追踪调用链路。对于Dubbo中的超时设置,可以在服务端、消费端,官方建议是设置在服务端,客户端做特殊处理即可,原因是服务端更清楚接口的性能情况。不过实际情况是,它仅将该参数传导到客户端,然后由客户端来控制。

标签:DUBBO,调用,dubbo,接口,设置,超时,浅析,服务端,客户端
From: https://blog.csdn.net/qq_40023049/article/details/143480500

相关文章

  • dubbo3.0 服务导入导出原理
    不管是服务导出还是服务引入,都发生在应用启动过程中,比如:在启动类上加上@EnableDubbo时,该注解上有一个@DubboComponentScan注解,@DubboComponentScan注解Import了一个DubboComponentScanRegistrar,DubboComponentScanRegistrar中会调用DubboSpringInitializer.initialize......
  • 浅析 C# 控制台的 Ctrl+C 是怎么玩的
    一:背景1.讲故事上一篇我们聊到了Console为什么会卡死,读过那篇文章的朋友相信对conhost.exe有了一个大概的了解,这一篇更进一步聊一聊窗口的特殊事件 Ctrl+C 底层流转到底是什么样的,为了方便讲述,让chagtgpt给我生成一段Ctrl+C的业务代码。classProgram{......
  • dubbo安装
    什么是dubbo?Dubbo是一款由阿里巴巴开源的高性能JavaRPC(RemoteProcedureCall,远程过程调用)框架。它旨在解决分布式服务架构中的服务治理、调用、容错等问题,使得开发者可以更加方便地构建和维护大规模分布式系统Dubbo是一个强大的分布式服务框架,适用于构建大规模的微服务......
  • 浅析Dockerhub API:如何优雅地从dockerhub偷rootfs镜像
    成品:https://github.com/Moe-hacker/docker_image_puller前言:八月初的时候,咱无聊去扒了下dockerhub的接口,想通过网络请求直接从dockerhub偷镜像。然后写完才想起来dockkerhub在国内是被墙的,似乎这么一个功能用处也不大。。。。。然后咱就去旅游了,连项目Readme都没写(逃)。至于......
  • 浅析双亲委派机制
    双亲委派机制1)什么是双亲委派虚拟机在加载类的过程中需要使用类加载器进行加载,而在Java中,类加载器有很多,那么当JVM想要加载一个.class文件的时候,到底应该由哪个类加载器加载呢?这就不得不提到"双亲委派机制"。首先,我们需要知道的是,Java语言系统中支持以下4种类加载器:Bootstrap......
  • 温习 SPI 机制 (Java SPI 、Spring SPI、Dubbo SPI)
    SPI全称为ServiceProviderInterface,是一种服务发现机制。SPI的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过SPI机制为我们的程序提供拓展功能。1JavaSPI......
  • dubbo3小记
    开启服务注册模式Dubbo3服务发现平滑迁移步骤与原理https://cn.dubbo.apache.org/zh-cn/blog/2024/05/13/如果从接口级服务发现平滑迁移到应用级服务发现/全局开关应用配置(可以通过配置文件或者-D指定)dubbo.application.register-mode为instance(只注册应用级)、all(接口级......
  • 【星闪开发连载】WS63E模块的雷达功能浅析
    目录引言功能简介程序分析操作步骤简单测试结语引言WS63E星闪模块有个特色功能就是雷达运动感知,检测物体是否有运动,作用距离不超过6米。hi3863芯片本身不带雷达功能,是模块提供的相关功能。海思还有个WS63星闪模块,没有雷达感知能力。功能简介从开发板的图片上可以......
  • 实战网络攻防中的高版本JDK反射类加载浅析
    就是要打骨折http://mp.weixin.qq.com/s?__biz=MzkwNjY1Mzc0Nw==&mid=2247486065&idx=2&sn=b30ade8200e842743339d428f414475e&chksm=c0e4732df793fa3bf39a6eab17cc0ed0fca5f0e4c979ce64bd112762def9ee7cf0112a7e76af&scene=21#wechat_redirect《Java代码审计》http:......
  • 智能手表核心芯片~手表心率监测芯片AFE4900浅析(附一篇智能手表专利推荐)
    智能手表核心芯片~手表心率监测芯片AFE4900浅析(附一篇智能手表专利推荐)本期是平台君和您分享的第89期内容2024年8月,安徽华米信息技术及美国的智能手表品牌ZEPP公司在美国对深圳思佰特公司提起诉讼,涉及专利、商标和不正当竞争。起诉书(来源:RPX网站)看到这则新闻,平台君马......