如何設置tomcat線程池大小?

背景

在咱們的平常開發中都涉及到使用tomcat作爲服務器,可是咱們該設置多大的線程池呢?以及根據什麼原則來設計這個線程池呢?接下來,我將介紹本人是怎麼設計以及計算的。java

具體方法

衆所周知,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時間呢? 這個就涉及到實際編碼過程當中的怎麼樣監控處理時間啦。tomcat

  • 經過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)app

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值來動態微調剛纔計算出的線程池大小。ide

相關文章
相關標籤/搜索