1. 程式人生 > >Dubbo 併發調優的幾個引數,dubbo併發調優引數

Dubbo 併發調優的幾個引數,dubbo併發調優引數

消費端調優:
一、connections
這個引數可以在服務提供端釋出服務的時候配置,也可以在消費端引用服務的時候配置,但是這個值是隻對消費端生效的,所以一般是服務提供端不建議配置,如果配置,請斟酌一下,詳情請檢視《對connections引數的設定 》。不管是在消費端或者服務提供端,如果對某個服務配置了connections引數,並且該引數大於1,那麼就會導致消費端在建立該服務的遠端socketclient的時候(如果是dubbo協議的話)將會給該服務初始化一個私有的socketclient。所以一般不建議對這個值進行調整。
服務端優化調整:
相對餘消費端,服務端調優的引數相對多一些,但是配置的時候也需要謹慎。

一、executes
這個引數是可以精確到方法級別的引數,就是可以指定呼叫遠端介面某個方法的是該引數的值。具體是怎麼配置的可以到官方文件裡面去看看那,這裡只是描述這個引數實際意義以及使用的時候應該注意點。

要說這個引數,就要所介紹ExecuteLimitFilter,他是這個引數使用者,看到Filter大家就應該懂了,就是在每個方法請求前後加上業務邏輯。下面貼出裡面的程式碼: 

@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) {
            RpcStatus count = RpcStatus.getStatus(url, invocation.getMethodName());
            if (count.getActive() >= max) {
                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);
        }
    }
     
}

上面這段程式碼主要是看兩個地方,分別是第7行和第10行,第7行是獲取配置的executes的值,是一個int型別的,描述數量,然後第10行是獲取當前請求方法當前的狀態,裡面既有一個active屬性(該屬性是AtomacInteger型別的,大家應該懂了為什麼用這個型別),表示當前請求的方法處於執行狀態的執行緒數量,如果這個值大於或者等於配置的值那麼直接丟擲異常,那麼消費端就會收到一個RPC的異常導致呼叫服務失敗,這是這個引數最終導致的效果。
二、actives
這個引數基本上和excetes一樣,但是有一點不同,在說這不同之前,還是看看另一個Filter,看名字你們應該就知道它是做什麼的了——ActiveLimitFilter,下面同樣貼出程式碼:

@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);
        RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
        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) {
                synchronized (count) {
                    while ((active = count.getActive()) >= max) {
                        try {
                            count.wait(remain);
                        } catch (InterruptedException e) {
                        }
                        long elapsed = System.currentTimeMillis() - start;
                        remain = timeout - elapsed;
                        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();
                }
            }
        }
    }
     
}
上面程式碼大致上和executes一樣,唯一不同的就是多了一個等待時間,噹噹前執行該方法的執行緒超出了最大限制,那麼可以等待一個timeout時間,如果時間過了還是超出了最大限制,那麼就丟擲異常。這個相對餘executes來說溫柔那麼點。這就是那點不同!
三、accepts 
在看程式碼之前先看看這個引數的意思,這個引數是告知服務提供端能接收多少個消費端連線該服務提供方。下面接著上程式碼,這個引數的體現是在類AbstractServer中。程式碼如下:


要說這個引數,就要所介紹ExecuteLimitFilter,他是這個引數使用者,看到Filter大家就應該懂了,就是在每個方法請求前後加上業務邏輯。下面貼出裡面的程式碼: 

@Override
    public void connected(Channel ch) throws RemotingException {
        Collection<Channel> channels = getChannels();
        if (accepts > 0 && channels.size() > accepts) {
            logger.error("Close channel " + ch + ", cause: The server " + ch.getLocalAddress() + " connections greater than max config " + accepts);
            ch.close();
            return;
        }
        super.connected(ch);
    }

這個方法是每個消費端向服務提供端建立一個socket連線的時候都會觸發,上面可以清晰看到如果連線當前服務端的消費端數量超出了配置的值,那麼將會關閉當前消費端連線的請求。這個只是對socket連線的數量限制,而不是像上面兩個引數對呼叫執行緒的配置。

以上歸納出的幾個引數建議服務端生效的在服務端配置,消費端生效的在消費端配置,不然會導致一些不可控的現象出現。這也叫改哪裡的東西就應該在哪裡,而不能亂放。