SpringBoot監控Tomcat活動線程數來判斷是否完成請求處理方式

SpringBoot監控Tomcat活動線程數來判斷是否完成請求處理

最近項目中有一個需求,需要判斷應用的請求是否已經處理完畢,想瞭一下,打算通過定時任務定時監控Tomcat的活動線程數來實現。

編碼實現

新建一個SpringBoot工程,添加定時任務定時監控,代碼如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class TomcatMonitor {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    ServletWebServerApplicationContext applicationContext;


    @Scheduled(cron = "*/1 * * * * ?")
    public void execute() {
        TomcatWebServer webServer = (TomcatWebServer) applicationContext.getWebServer();
        String tomcatInfo = webServer.getTomcat().getConnector().getProtocolHandler().getExecutor().toString();

        System.out.println("tomcatInfo: " + tomcatInfo);
    }

}

測試

新建一個測試請求類,代碼如下:

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class TestController {

    @RequestMapping("/test")
    public String test() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("complete OK");
        return "OK";
    }

}

啟動項目:

tomcatInfo: org.apache.tomcat.util.threads.ThreadPoolExecutor@49355b92[Running, pool size = 10, active threads = 0, queued tasks = 0, completed tasks = 0]
tomcatInfo: org.apache.tomcat.util.threads.ThreadPoolExecutor@49355b92[Running, pool size = 10, active threads = 0, queued tasks = 0, completed tasks = 0]

訪問測試接口,觀察Tomcat線程池變化:

tomcatInfo: org.apache.tomcat.util.threads.ThreadPoolExecutor@49355b92[Running, pool size = 10, active threads = 1, queued tasks = 0, completed tasks = 0]
complete OK
tomcatInfo: org.apache.tomcat.util.threads.ThreadPoolExecutor@49355b92[Running, pool size = 10, active threads = 0, queued tasks = 0, completed tasks = 2]

可以看到,當有請求處理時,Tomcat的活動線程數不為0,處理完成以後回歸到0,所以可以通過活動線程數判斷當前Tomcat是否有請求還在處理,當然,應用到實際業務中,還有需要完善的地方。

Tomcat線程數占滿而導致的線上事故

事故表現形式

昨天下午4點多的時候,有同學反映說,某個服務響應時間過長,懷疑是負載均衡的問題。

排查過程

1,查看阿裡雲負載均衡表現正常,排除。

2,查看單臺服務日志出現OOM,可以斷定是服務出問題瞭。

分析原因

1,先重啟服務。

2,下載 *.hprof 日志,用MAT分析結果如下圖:

3,結果明顯指示tomcat線程池滿瞭,並指向瞭其中一個controller的外部請求。

4,結合代碼分析是請求外部HTTP連接沒有設置超時時間,導致大量請求堆積,tomcat線程池滿瞭,造成OOM。

解決辦法

1,HTTP請求使用連接池,設置超時響應時間

2,加上監控。

總結

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: