背景
在我們的日常開發中都涉及到使用tomcat做為伺服器,但是我們該設定多大的執行緒池呢?以及根據什麼原則來設計這個執行緒池呢?接下來,我將介紹本人是怎麼設計以及計算的。
具體方法
眾所周知,tomcat接受一個request後處理過程中,會涉及到cpu和IO時間。其中IO等待時間,cpu被動放棄執行,其他執行緒就可以利用這段時間片進行操作。所以我們可以採用伺服器IO優化的通用規則。執行緒大小 = ( (執行緒io時間 + 執行緒cpu) / 執行緒cpu time) * cpu核數
舉例
執行緒io時間為100ms(IO操作比如資料庫查詢,同步遠端呼叫等),執行緒cpu時間10ms,伺服器物理機核數為4個。通過上面的公式,我們計算出來的大小是 ((100 + 10 )/10 ) *4 = 44
。理論上我們有依據,但是實際計算過程中我們怎麼知道執行緒IO時間和cpu時間呢? 這個就涉及到實際編碼過程中的怎麼樣監控處理時間啦。
-
通過java 實現內建的filter介面,我們可以拿到一個request消耗的總時間
public class MoniterFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException,
ServletException {
long start = System.currentTimeMillis();
String params = getQueryString(httpRequest);
try {
chain.doFilter(httpRequest, httpResponse);
} finally {
logger.info("access url [{}{}], cost time [{}] ms )", uri,
params, cost);
}
private String getQueryString(HttpServletRequest req) {
StringBuilder buffer = new StringBuilder("?");
Enumeration<String> emParams = req.getParameterNames();
try {
while (emParams.hasMoreElements()) {
String sParam = emParams.nextElement();
String sValues = req.getParameter(sParam);
buffer.append(sParam).append("=").append(sValues).append("&");
}
return buffer.substring(0, buffer.length() - 1);
} catch (Exception e) {
}
return "";
}
}
-
通過新增切面來監控執行緒IO耗時(jdk,cglib)
public class DaoInterceptor implements MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(DaoInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
StopWatch watch = new StopWatch();
watch.start();
Object result = null;
Throwable t = null;
try {
result = invocation.proceed();
} catch (Throwable e) {
t = e == null ? null : e.getCause();
throw e;
} finally {
watch.stop();
logger.info("({}ms)", watch.getTotalTimeMillis());
}
return result;
}
}
通過上述程式碼就可以計算出相應時間,從而計算出執行緒大小啦。但是我們就到此為止了嗎?
其實還沒有,計算出的數值只是存在理論情況下,我們還是需要通過壓測工具(Jmeter)來壓測一下線伺服器,同時根據qps值來動態微調剛才計算出的執行緒池大小。