dubbo超時異常

dubbo超時異常

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

相關文章
相關標籤/搜索