在调用dubbo服务时常常看到以下错误: Caused by: com.alibaba.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer.ide
客户端调用远程服务时,本地会生成一个DefaultFuture,调用DefaultFuture.get()获取远程服务返回的结构,此方法获取锁,调用await方法,此时当前线程进入等待队列,此线程会有两种结果过:要么超时,抛出TimeOutException;若是被唤醒,则返回rpc的结果。 而这里的报错很明显是因为等待服务端返回结果时客户端超时异常,查看源码以下:源码分析
public class DefaultFuture implements ResponseFuture { private static final Logger logger = LoggerFactory.getLogger(DefaultFuture.class); private static final Map<Long, Channel> CHANNELS = new ConcurrentHashMap<Long, Channel>(); private static final Map<Long, DefaultFuture> FUTURES = new ConcurrentHashMap<Long, DefaultFuture>(); // invoke id. private final long id; private final Channel channel; private final Request request; private final int timeout; private final Lock lock = new ReentrantLock(); private final Condition done = lock.newCondition(); private final long start = System.currentTimeMillis(); private volatile long sent; private volatile Response response; private volatile ResponseCallback callback; public DefaultFuture(Channel channel, Request request, int timeout){ this.channel = channel; this.request = request; this.id = request.getId(); this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT); // put into waiting map. FUTURES.put(id, this); CHANNELS.put(id, channel); } public Object get() throws RemotingException { return get(timeout); } 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); 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(); } }
这里的超时时间设置的是1sthis
public static final int DEFAULT_TIMEOUT = 1000;
检查消费者配置查看是否配置总的超时时长,这里建议配置一个总的,我因为没配置致使使用的是默认配置使得超过1s就报错。线程
<dubbo:consumer timeout="5000" />
也能够在消费者端对每一个服务自定义配置日志
<dubbo:reference interface="com.foo.BarService" timeout="2000"/>
这里也须要注意服务端也有一个超时时间code
<dubbo:provider timeout="5000"/>
<dubbo:provider interface="com.foo.BarService" timeout="5000">
当客户端timeout值>服务端timeout值,会出现超时日志,可是仍然能够获取到结果。客户端timeout超时抛出异常时,有一个线程RemotingInvocationTimeoutScan会自动清理对应超时的Future。server