在調用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