一、准备

1、服务器

  1. 为了保证尽量少的干扰,这里不再在虚拟机上运行服务,而是直接在物理机上运行服务,并且在这台物理机上安装ab工具。<br /> 服务器配置是2CPU,单个CPU8核,总共内存40G1TRAID5机械硬盘。服务器安装的系统是Centos7.5,系统优化同《[Centos7高并发优化](https://my.oschina.net/shyloveliyi/blog/2979058)》所述。但额外的,因工作需要,这台物理机上有6个虚机,是不能关闭的。以下是简单的top展示:<br />![](https://cdn.nlark.com/yuque/0/2019/jpeg/165373/1574234109817-cd919540-3172-4342-970b-24bb9609d0dc.jpeg#align=left&display=inline&height=863&originHeight=863&originWidth=2230&size=0&status=done&width=2230)<br />

2、测试项目

  1. 感谢@[TGVvbmFyZA](https://my.oschina.net/L3on4Rd) 的建议,测试项目不再使用生产项目,而是从Springboot官网打包2.x版本的项目,这样的目的是减少生产项目中不必要的依赖,从而避免不必要的开销。以下是简单的项目介绍:
序号 名称 版本
1 springboot 2.1.1
2 java 1.8
  1. 我已将项目放到Gitee,地址:https://gitee.com/loveliyiyi/test4server<br /> 以下贴出关键代码,以便更好理解。
  1. package com.shy.test4server;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.context.request.async.WebAsyncTask;
  6. /**
  7. * @ClassName: TestController
  8. * @Description: TODO(这里用一句话描述这个类的作用)
  9. * @author chengcai.shang@cmgplex.com
  10. * @date 2018年12月7日 上午9:36:25
  11. *
  12. */
  13. @Controller
  14. @RequestMapping("/test")
  15. public class TestController {
  16. /**
  17. * 未使用HTTP异步的接口
  18. *
  19. * @Title: testCeilingNoAsync
  20. * @Description: TODO(这里用一句话描述这个方法的作用)
  21. * @date 2018年12月7日 上午9:40:57
  22. */
  23. @GetMapping("/testCeilingNoAsync")
  24. public String testCeilingNoAsync() {
  25. return "";
  26. }
  27. /**
  28. * 使用HTTP异步的接口
  29. *
  30. * @Title: testCeilingNoAsync
  31. * @Description: TODO(这里用一句话描述这个方法的作用)
  32. * @date 2018年12月7日 上午9:40:57
  33. */
  34. @GetMapping("/testCeilingWithAsync")
  35. public WebAsyncTask<String> testCeilingWithAsync() {
  36. return new WebAsyncTask(() -> {
  37. return "";
  38. });
  39. }
  40. }

3、项目优化

  1. 不同的服务器容器优化参数均不一致,以下是本次测试主要优化的地方:
序号 服务容器 优化参数
1 tomcat 最大连接数server.tomcat.max-threads=400
2 jetty 最大连接数(400)和最小连接数(10)
3 undertow cpu核数(16)和工作线程数(400)
4 http异步 线程池core=10,max=400,queue=200
  1. 以下优化步骤:<br /> 针对tomcat,在application.properties中加入server.tomcat.max-threads=400即可。<br /> 针对jetty,在config目录加入JettyConfig
  1. package com.shy.test4server.config;
  2. import org.apache.catalina.Server;
  3. import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. /**
  7. * @ClassName: JettyConfig
  8. * @Description: TODO(这里用一句话描述这个类的作用)
  9. * @date 2018年12月7日 上午9:53:46
  10. *
  11. */
  12. @Configuration
  13. public class JettyConfig {
  14. @Bean
  15. public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory(
  16. JettyServerCustomizer jettyServerCustomizer) {
  17. JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
  18. factory.addServerCustomizers(jettyServerCustomizer);
  19. return factory;
  20. }
  21. @Bean
  22. public JettyServerCustomizer jettyServerCustomizer() {
  23. return server -> {
  24. threadPool(server);
  25. };
  26. }
  27. private void threadPool(Server server) {
  28. // Tweak the connection config used by Jetty to handle incoming HTTP
  29. // connections
  30. final QueuedThreadPool threadPool = server.getBean(QueuedThreadPool.class);
  31. // 默认最大线程连接数200
  32. threadPool.setMaxThreads(100);
  33. // 默认最小线程连接数8
  34. threadPool.setMinThreads(20);
  35. // 默认线程最大空闲时间60000ms
  36. threadPool.setIdleTimeout(60000);
  37. }
  38. }
  1. 针对undertow,在application.properties中加入server.undertow.io-threads=16server.undertow.worker-threads=400即可<br /> 针对http异步,优化代码如下:
  1. package com.shy.test4server.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  5. import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
  6. /**
  7. * @ClassName: SpringmvcConfig
  8. * @Description: TODO(这里用一句话描述这个类的作用)
  9. * @date 2018年12月7日 上午9:59:06
  10. *
  11. */
  12. @Configuration
  13. public class SpringmvcConfig {
  14. @Bean
  15. public void configThreadPoll(AsyncSupportConfigurer asyncSupportConfigurer) {
  16. ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
  17. threadPool.setCorePoolSize(10);
  18. threadPool.setMaxPoolSize(400);
  19. threadPool.setQueueCapacity(200);
  20. threadPool.initialize();
  21. asyncSupportConfigurer.setTaskExecutor(threadPool);
  22. }
  23. }
  1. 另,所有测试中,日志均关闭。<br />

二、压测方案

  1. 由于三个服务器的优化参数不一致,没法做统一配置,然后观察结果。故只能不断调整参数获取最大的结果,然后比对最终结果,虽然这样得出结果有点片面,但目前也只能这么干。另外,不再辅以Jprofiler监控,因为Jprofiler会影响一定得性能。以下是压测步骤:<br /> 1、使用tomcat,压测两个接口,按不同并发访问10000次,然后不断调整参数,获取最大结果。由此可得出纯tomcattomcat+http异步的结果。<br /> 2、使用jetty,压测两个接口,按不同并发访问10000次,然后不断调整参数,获取最大结果。由此可得出纯jettyjetty+http异步的结果。<br /> 3、使用udertow,压测两个接口,按不同并发访问10000次,然后不断调整参数,获取最大结果。由此可得出纯udertowudertow+http异步的结果。<br />

三、压测过程

1、tomcat

  1. 启动命令
  1. java -server -Dserver.tomcat.max-threads=400 -Dspringmvc.thread.core=10 -Dspringmvc.thread.max=400 -Dspringmvc.thread.queue=200 -Xms512m -Xmx512m -jar test4server.jar
  1. 压测命令
  1. ab -n 10000 -c 50 http://localhost:8080/test/testCeilingNoAsync
  2. ab -n 10000 -c 100 http://localhost:8080/test/testCeilingNoAsync
  3. ab -n 10000 -c 200 http://localhost:8080/test/testCeilingNoAsync
  4. ab -n 10000 -c 50 http://localhost:8080/test/testCeilingWithAsync
  5. ab -n 10000 -c 100 http://localhost:8080/test/testCeilingWithAsync
  6. ab -n 10000 -c 200 http://localhost:8080/test/testCeilingWithAsync
  1. 压测结果:<br />![](https://cdn.nlark.com/yuque/0/2019/jpeg/165373/1574234110038-aae39bc3-9723-4eef-ac47-469d06047319.jpeg#align=left&display=inline&height=215&originHeight=215&originWidth=564&size=0&status=done&width=564)<br />

2、jetty

  1. 启动命令
  1. 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
  1. 压测命令
  1. ab -n 10000 -c 50 http://localhost:8080/test/testCeilingNoAsync
  2. ab -n 10000 -c 100 http://localhost:8080/test/testCeilingNoAsync
  3. ab -n 10000 -c 200 http://localhost:8080/test/testCeilingNoAsync
  4. ab -n 10000 -c 50 http://localhost:8080/test/testCeilingWithAsync
  5. ab -n 10000 -c 100 http://localhost:8080/test/testCeilingWithAsync
  6. ab -n 10000 -c 200 http://localhost:8080/test/testCeilingWithAsync
  1. 压测结果:<br />![](https://cdn.nlark.com/yuque/0/2019/jpeg/165373/1574234110025-529de08a-0ac9-4127-91a7-6230102d94b0.jpeg#align=left&display=inline&height=316&originHeight=316&originWidth=733&size=0&status=done&width=733)<br />

3、undertow

  1. 启动命令
  1. 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
  1. 压测命令
  1. ab -n 10000 -c 50 http://localhost:8080/test/testCeilingNoAsync
  2. ab -n 10000 -c 100 http://localhost:8080/test/testCeilingNoAsync
  3. ab -n 10000 -c 200 http://localhost:8080/test/testCeilingNoAsync
  4. ab -n 10000 -c 50 http://localhost:8080/test/testCeilingWithAsync
  5. ab -n 10000 -c 100 http://localhost:8080/test/testCeilingWithAsync
  6. ab -n 10000 -c 200 http://localhost:8080/test/testCeilingWithAsync
  1. 压测结果:<br />![](https://cdn.nlark.com/yuque/0/2019/jpeg/165373/1574234109855-5ce2d0a3-7f96-4a4c-a068-a74695e0e6ba.jpeg#align=left&display=inline&height=319&originHeight=319&originWidth=733&size=0&status=done&width=733)<br />

四、压测结果

1、关于HTTP异步

  1. HTTP异步的目的在帮助dispatcherservlet分担压力,提升吞吐量。但如果运行在NIO模式的服务容器上,就会产生负面影响,因为NIO本身就做了类似的事情,此时再加HTTP异步,则相当于又加了N多不必要的线程,导致性能主要消耗在线程的开销上,所以建议使用tomcat作为内嵌容器并且没有开启tomcatNIO模式时,可以配合HTTP异步来提升程序性能。尤其是当业务繁重时,提升效果尤其明显。<br />

2、关于服务容器

  1. 在基于天花板接口的测试中,综合对比tomcatjettyundertow,可以发现undertow相对性能更高点。但此结果并不一定准确,因为测试方案里只进行了很简单的参数调整,以及并没有针对实际业务代码进行测试。

原文:https://my.oschina.net/shyloveliyi/blog/2980868?from=singlemessage