如何計算tomcat線程池大小?


  • 背景

  在我們的日常開發中都涉及到使用tomcat做為服務器,但是我們該設置多大的線程池呢?以及根據什么原則來設計這個線程池呢?

  接下來,我將介紹本人是怎么設計以及計算的。

  • 目標

  確定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時間呢? 這個就涉及到實際編碼過程中的怎么樣監控處理時間啦。

下面我介紹本人項目中的做法

  1. 通過java 實現內置的filter接口,我們可以拿到一個request消耗的總時間

public class MoniterFilter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(MoniterFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
        long start = System.currentTimeMillis();

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        String uri = httpRequest.getRequestURI();
        String params = getQueryString(httpRequest);

        try {
            chain.doFilter(httpRequest, httpResponse);
        } finally {
            long cost = System.currentTimeMillis() - start;
            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) {
            logger.error("get post arguments error", buffer.toString());
        }
        return "";
    }

    @Override
    public void destroy() {
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

}

  2. 通過添加切面來監控線程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值來動態微調剛才計算出的線程池大小。

如果文章還對大家有實際意義,請推薦一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM