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連接的數量限制,而不是像上面兩個參數對調用線程的配置。???
五,總結:
以上歸納出的幾個參數建議服務端生效的在服務端配置,消費端生效的在消費端配置,不然會導致一些不可控的現象出現。這也叫改哪裏的東西就應該在哪裏,而不能亂放。
Dubbo 並發調優的幾個參數