(十一)併發控制

一、消費者併發控制

消費者對同一個方法可以進行併發數的控制,dubbo也是基於過濾器的設置功能來實現併發控制的。

通過配置actives的值,在可以Consumer配置,也可以在Provider配置,一般可以在提供者配置的,可以在提供者配置,提供者比較清楚服務能夠承受的併發數。
actives默認 0 每服務消費者每服務每方法最大併發調用數

@Activate(group = Constants.CONSUMER, value = Constants.ACTIVES_KEY)
public class ActiveLimitFilter implements Filter {

    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        URL url = invoker.getUrl();
        String methodName = invocation.getMethodName();
        int max = invoker.getUrl().getMethodParameter(methodName, Constants.ACTIVES_KEY, 0); //21處,獲取actives配置項的值
        RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()); //22處
        if (max > 0) {
            long timeout = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.TIMEOUT_KEY, 0);
            long start = System.currentTimeMillis();
            long remain = timeout;
            int active = count.getActive();
            if (active >= max) { //23處
                synchronized (count) { //24處
                    while ((active = count.getActive()) >= max) {
                        try {
                            count.wait(remain); //25處
                        } catch (InterruptedException e) {
                        }
                        long elapsed = System.currentTimeMillis() - start;
                        remain = timeout - elapsed; //26處
                        if (remain <= 0) {
                            throw new RpcException("Waiting concurrent invoke timeout in client-side for service:  "
                                                   + invoker.getInterface().getName() + ", method: "
                                                   + invocation.getMethodName() + ", elapsed: " + elapsed
                                                   + ", timeout: " + timeout + ". concurrent invokes: " + active
                                                   + ". max concurrent invoke limit: " + max);
                        }
                    }
                }
            }
        }
        try {
            long begin = System.currentTimeMillis();
            RpcStatus.beginCount(url, methodName);
            try {
                Result result = invoker.invoke(invocation);
                RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, true);
                return result;
            } catch (RuntimeException t) {
                RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, false);
                throw t;
            }
        } finally {
            if(max>0){
                synchronized (count) {
                    count.notify();
                }
            }
        }
    }

}

在"21處",獲取配置的屬性值,然後"22處",獲取方法的併發數。
RpcStatus使用一個map保存了方法的併發數:

public static RpcStatus getStatus(URL url, String methodName) {
    String uri = url.toIdentityString();
    ConcurrentMap<String, RpcStatus> map = METHOD_STATISTICS.get(uri);
    if (map == null) {
        METHOD_STATISTICS.putIfAbsent(uri, new ConcurrentHashMap<String, RpcStatus>());
        map = METHOD_STATISTICS.get(uri);
    }
    RpcStatus status = map.get(methodName);
    if (status == null) {
        map.putIfAbsent(methodName, new RpcStatus());
        status = map.get(methodName);
    }
    return status;
}

在上面的"23處",如果方法調用數已經達到 最大併發數,則"24處"會使用鎖,使得消息者進行排隊,獲得鎖後,並且 併發數 還是 達到併發數的話,"25處"會等待,"26處"判斷是否等等超時,超時則拋出超時異常。

 

二、提供者併發控制

提供者對同一個方法可以進行併發數的控制,dubbo也是基於過濾器的設置功能來實現併發控制的。
可能通過配置executes屬性來控制提供者服務被調用的數量
executes 默認0 服務提供者每服務每方法最大可並行執行請求數

下面是源碼

@Activate(group = Constants.PROVIDER, value = Constants.EXECUTES_KEY)
public class ExecuteLimitFilter implements Filter {

    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        URL url = invoker.getUrl();
        String methodName = invocation.getMethodName();
        int max = url.getMethodParameter(methodName, Constants.EXECUTES_KEY, 0);
        if (max > 0) { //31處
            RpcStatus count = RpcStatus.getStatus(url, invocation.getMethodName());
            if (count.getActive() >= max) { //32處
                throw new RpcException("Failed to invoke method " + invocation.getMethodName() + " in provider " + url + ", cause: The service using threads greater than <dubbo:service executes=\"" + max + "\" /> limited.");
            }
        }
        long begin = System.currentTimeMillis();
        boolean isException = false;
        RpcStatus.beginCount(url, methodName);
        try {
            Result result = invoker.invoke(invocation);
            return result;
        } catch (Throwable t) {
            isException = true;
            if(t instanceof RuntimeException) {
                throw (RuntimeException) t;
            }
            else {
                throw new RpcException("unexpected exception when ExecuteLimitFilter", t);
            }
        }
        finally {
            RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, isException);
        }
    }

}

從上面源碼的31處,32處,可以知道提供者的併發控制 和 消費者的併發控制 有點類似,不同的是,提供者一旦達到最大併發數,不會有排隊超時機制,提供者會馬止拋出異常。

額外還有一個配置屬性connections,默認值100,每個服務對每個提供者的最大連接數,rmi、http、hessian等短連接協議支持此配置,dubbo協議長連接不支持此配置

自己寫了個RPC:

https://github.com/nytta

可以給個star,^0^.

發佈了184 篇原創文章 · 獲贊 60 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章