後續之《SpringBoot伺服器壓測對比(jetty、tomcat、undertow)》
一、前言
昨天發了一個《SpringBoot伺服器壓測對比(jetty、tomcat、undertow)》,本是工作的一個筆記,沒想到被紅薯翻牌了(榮幸之至)。看了OSCer的回覆,感覺需要重新梳理下,因為確實存在描述不清和不合理的配置。
這篇部落格的目的,不是複述上一篇部落格,而是儘量規範的去做一次壓測對比,並且能夠清晰的描述出過程和結果。
二、準備
1、伺服器
為了保證儘量少的干擾,這裡不再在虛擬機器上執行服務,而是直接在物理機上執行服務,並且在這臺物理機上安裝ab工具。
伺服器配置是2個CPU,單個CPU8核,總共記憶體40G,1T的RAID5機械硬碟。伺服器安裝的系統是Centos7.5,系統優化同《Centos7高併發優化》所述。但額外的,因工作需要,這臺物理機上有6個虛機,是不能關閉的。以下是簡單的top展示:
2、測試專案
感謝@TGVvbmFyZA 的建議,測試專案不再使用生產專案,而是從Springboot官網打包2.x版本的專案,這樣的目的是減少生產專案中不必要的依賴,從而避免不必要的開銷。以下是簡單的專案介紹:
序號 | 名稱 | 版本 |
1 | springboot | 2.1.1 |
2 | java | 1.8 |
我已將專案放到Gitee,地址:https://gitee.com/loveliyiyi/test4server
以下貼出關鍵程式碼,以便更好理解。
package com.shy.test4server;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.async.WebAsyncTask;
/**
* @ClassName: TestController
* @Description: TODO(這裡用一句話描述這個類的作用)
* @author [email protected]
* @date 2018年12月7日 上午9:36:25
*
*/
@Controller
@RequestMapping("/test")
public class TestController {
/**
* 未使用HTTP非同步的介面
*
* @Title: testCeilingNoAsync
* @Description: TODO(這裡用一句話描述這個方法的作用)
* @date 2018年12月7日 上午9:40:57
*/
@GetMapping("/testCeilingNoAsync")
public String testCeilingNoAsync() {
return "";
}
/**
* 使用HTTP非同步的介面
*
* @Title: testCeilingNoAsync
* @Description: TODO(這裡用一句話描述這個方法的作用)
* @date 2018年12月7日 上午9:40:57
*/
@GetMapping("/testCeilingWithAsync")
public WebAsyncTask<String> testCeilingWithAsync() {
return new WebAsyncTask(() -> {
return "";
});
}
}
3、專案優化
不同的伺服器容器優化引數均不一致,以下是本次測試主要優化的地方:
序號 | 服務容器 | 優化引數 |
1 | tomcat | 最大連線數server.tomcat.max-threads=400 |
2 | jetty | 最大連線數(400)和最小連線數(10) |
3 | undertow | cpu核數(16)和工作執行緒數(400) |
4 | http非同步 | 執行緒池core=10,max=400,queue=200 |
以下優化步驟:
針對tomcat,在application.properties中加入server.tomcat.max-threads=400即可。
針對jetty,在config目錄加入JettyConfig類
package com.shy.test4server.config;
import org.apache.catalina.Server;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName: JettyConfig
* @Description: TODO(這裡用一句話描述這個類的作用)
* @date 2018年12月7日 上午9:53:46
*
*/
@Configuration
public class JettyConfig {
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory(
JettyServerCustomizer jettyServerCustomizer) {
JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
factory.addServerCustomizers(jettyServerCustomizer);
return factory;
}
@Bean
public JettyServerCustomizer jettyServerCustomizer() {
return server -> {
threadPool(server);
};
}
private void threadPool(Server server) {
// Tweak the connection config used by Jetty to handle incoming HTTP
// connections
final QueuedThreadPool threadPool = server.getBean(QueuedThreadPool.class);
// 預設最大執行緒連線數200
threadPool.setMaxThreads(100);
// 預設最小執行緒連線數8
threadPool.setMinThreads(20);
// 預設執行緒最大空閒時間60000ms
threadPool.setIdleTimeout(60000);
}
}
針對undertow,在application.properties中加入server.undertow.io-threads=16和server.undertow.worker-threads=400即可
針對http非同步,優化程式碼如下:
package com.shy.test4server.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
/**
* @ClassName: SpringmvcConfig
* @Description: TODO(這裡用一句話描述這個類的作用)
* @date 2018年12月7日 上午9:59:06
*
*/
@Configuration
public class SpringmvcConfig {
@Bean
public void configThreadPoll(AsyncSupportConfigurer asyncSupportConfigurer) {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(10);
threadPool.setMaxPoolSize(400);
threadPool.setQueueCapacity(200);
threadPool.initialize();
asyncSupportConfigurer.setTaskExecutor(threadPool);
}
}
另,所有測試中,日誌均關閉。
三、壓測方案
由於三個伺服器的優化引數不一致,沒法做統一配置,然後觀察結果。故只能不斷調整引數獲取最大的結果,然後比對最終結果,雖然這樣得出結果有點片面,但目前也只能這麼幹。另外,不再輔以Jprofiler監控,因為Jprofiler會影響一定得效能。以下是壓測步驟:
1、使用tomcat,壓測兩個介面,按不同併發訪問10000次,然後不斷調整引數,獲取最大結果。由此可得出純tomcat和tomcat+http非同步的結果。
2、使用jetty,壓測兩個介面,按不同併發訪問10000次,然後不斷調整引數,獲取最大結果。由此可得出純jetty和jetty+http非同步的結果。
3、使用udertow,壓測兩個介面,按不同併發訪問10000次,然後不斷調整引數,獲取最大結果。由此可得出純udertow和udertow+http非同步的結果。
四、壓測過程
1、tomcat
啟動命令
java -server -Dserver.tomcat.max-threads=400 -Dspringmvc.thread.core=10 -Dspringmvc.thread.max=400 -Dspringmvc.thread.queue=200 -Xms512m -Xmx512m -jar test4server.jar
壓測命令
ab -n 10000 -c 50 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 100 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 200 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 50 http://localhost:8080/test/testCeilingWithAsync
ab -n 10000 -c 100 http://localhost:8080/test/testCeilingWithAsync
ab -n 10000 -c 200 http://localhost:8080/test/testCeilingWithAsync
壓測結果:
2、jetty
啟動命令
java -server -Djetty.thread.max=400 -Djetty.thread.min=10 -Dspringmvc.thread.core=10 -Dspringmvc.thread.max=400 -Dspringmvc.thread.queue=200 -Xms512m -Xmx512m -jar test4server.jar
壓測命令
ab -n 10000 -c 50 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 100 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 200 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 50 http://localhost:8080/test/testCeilingWithAsync
ab -n 10000 -c 100 http://localhost:8080/test/testCeilingWithAsync
ab -n 10000 -c 200 http://localhost:8080/test/testCeilingWithAsync
壓測結果:
3、undertow
啟動命令
java -server -Dserver.undertow.io-threads=16 -Dserver.undertow.worker-threads=400 -Dspringmvc.thread.core=10 -Dspringmvc.thread.max=400 -Dspringmvc.thread.queue=200 -Xms512m -Xmx512m -jar test4server.jar
壓測命令
ab -n 10000 -c 50 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 100 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 200 http://localhost:8080/test/testCeilingNoAsync
ab -n 10000 -c 50 http://localhost:8080/test/testCeilingWithAsync
ab -n 10000 -c 100 http://localhost:8080/test/testCeilingWithAsync
ab -n 10000 -c 200 http://localhost:8080/test/testCeilingWithAsync
壓測結果:
五、壓測結果
1、關於HTTP非同步
HTTP非同步的目的在幫助dispatcherservlet分擔壓力,提升吞吐量。但如果執行在NIO模式的服務容器上,就會產生負面影響,因為NIO本身就做了類似的事情,此時再加HTTP非同步,則相當於又加了N多不必要的執行緒,導致效能主要消耗線上程的開銷上,所以建議使用tomcat作為內嵌容器並且沒有開啟tomcat的NIO模式時,可以配合HTTP非同步來提升程式效能。尤其是當業務繁重時,提升效果尤其明顯。
2、關於服務容器
在基於天花板介面的測試中,綜合對比tomcat、jetty、undertow,可以發現undertow相對效能更高點。但此結果並不一定準確,因為測試方案裡只進行了很簡單的引數調整,以及並沒有針對實際業務程式碼進行測試。不過原始碼我已提供,有興趣的可以實際測試下。