dubbo 有服务端和客户端两个地方设置timeout
// 服务端
<dubbo:service ref="xxxService" interface="com.xxx.XxxService" timeout="5000" />
// 客户端
<dubbo:reference id="xxxService" interface="com.xxx.XxxService" timeout="10000" />
客户端调用远程服务时,本地会生成一个DefaultFuture,调用DefaultFuture.get()获取远程服务返回的结构,此方法获取锁,调用await方法,此时当前线程进入等待队列,此线程会有两种结果过:要么超时,抛出TimeOutException;如果被唤醒,则返回rpc的结果
在服务端timeout时间为5s,如果实际的数据操作耗时7s,服务端TimeoutFilter会根据服务端timeout检测到操作超时,打出warn日志。
在第7s,客户端接收到数据包,客户端timeout设置为10s>7s,DefaultFuture被唤醒,仍然可以接收到Rpc返回值。
public Object get(int timeout) throws RemotingException {
if (timeout <= 0) {
timeout = Constants.DEFAULT_TIMEOUT;
}
if (! isDone()) {
long start = System.currentTimeMillis();
lock.lock();//加锁
try {
while (! isDone()) {
done.await(timeout, TimeUnit.MILLISECONDS); //等待timeout
if (isDone() || System.currentTimeMillis() - start > timeout) {
break;
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
if (! isDone()) {// 客户端超时仍然没有得到服务端返回,抛出异常
throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
}
}
return returnFromResponse();
}
如果超出了10s还没有返回值,抛出TimeoutException。
此时这个DefaultFuture超时了,有一个线程RemotingInvocationTimeoutScan,清理所有超时的DefaultFuture,创建一个timeoutResponse,DefaultFuture.received这样的response就会抛出TimeoutException。
综上所诉:当客户端timeout值>服务端timeout值,会出现超时日志,但是仍然可以获取到结果。客户端timeout超时抛出异常时,对应超时的Future会自动清理。