系统性能优化要具体问题具体分析

之前把自己开发的一个系统中的某个交易做了改造,使用了servlet 3.0的异步处理特性,将每个servlet线程内的业务逻辑改成了非阻塞式的,期望容器线程能够更快速的返回并充分利用处理更多的请求,从而得到更强的 并发处理能力。但是测试的结果很不理想,同样的业务逻辑模块,采用新的异步调用之后的并发度甚至赶不上原来的传统方式(在一个servlet线程内处理业 务逻辑并返回,属于阻塞式)。

     InfoQ上的一位架构师的演讲中的一话提醒了我,是否对于目前的测试案例,瓶颈并不是在线程池,而是在CPU等其他系统资源呢?

     测试的这个业务模块中包括有数据库调用,业务数据的计算,日志,以及xml解析返回等等,可能会造成其他系统资源的瓶颈,既然目的是测试异步调用对容器线程充分利用的优势,那么应该突出线程资源这个主要矛盾。

     修改需要调用的业务模块,使之只是简单的实现一个返回html的功能,而在其中使用线程休眠等待几百毫秒来模拟业务执行(保证只是时间上的等待而不占用更多的系统资源)。调整服务器配置,减少容器线程池中线程数,使容器线程资源紧张暴露出来。

服务器配置:

Xml代码   收藏代码
  1. <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"  
  2.   
  3.         maxThreads="90" minSpareThreads="15" />  
  4.   
  5.  <Connector executor="tomcatThreadPool"  
  6.   
  7.                port="8080" protocol="HTTP/1.1"  
  8.   
  9.                connectionTimeout="20000"  
  10.   
  11.                redirectPort="8443"   
  12.   
  13.                processorCache="2000"  
  14.   
  15.                acceptCount="100" URIEncoding="GBK" useBodyEncodingForURI="true"/>  


Java代码:


传统方式:


Java代码   收藏代码
  1. package servlets;  
  2.   
  3.    
  4.   
  5. import java.io.IOException;  
  6.   
  7. import java.io.PrintWriter;  
  8.   
  9.    
  10.   
  11. import javax.servlet.ServletException;  
  12.   
  13. import javax.servlet.http.HttpServlet;  
  14.   
  15. import javax.servlet.http.HttpServletRequest;  
  16.   
  17. import javax.servlet.http.HttpServletResponse;  
  18.   
  19.    
  20.   
  21. public class CommonProcessServlet extends HttpServlet{  
  22.   
  23.    
  24.   
  25. /** 
  26.  
  27. *    传统方式在同一个servlet线程内处理业务逻辑,处理完毕后返回,属于阻塞式。 
  28.  
  29. */  
  30.   
  31. private static final long serialVersionUID = 1L;  
  32.   
  33. public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{  
  34.   
  35. try {  
  36.   
  37. Thread.sleep(200);  
  38.   
  39. catch (InterruptedException e) {  
  40.   
  41. e.printStackTrace();  
  42.   
  43. }  
  44.   
  45. response.setContentType("text/html");  
  46.   
  47. PrintWriter out = response.getWriter();  
  48.   
  49. out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">");  
  50.   
  51. out.println("<html>");  
  52.   
  53. out.println("Hello,world!");  
  54.   
  55. out.println("</html>");  
  56.   
  57. }  
  58.   
  59. }  


servlet 3.0异步方式:


Java代码   收藏代码
  1. package servlets;  
  2.   
  3.    
  4.   
  5. import java.io.IOException;  
  6.   
  7.    
  8.   
  9. import javax.servlet.AsyncContext;  
  10.   
  11. import javax.servlet.ServletException;  
  12.   
  13. import javax.servlet.http.HttpServlet;  
  14.   
  15. import javax.servlet.http.HttpServletRequest;  
  16.   
  17. import javax.servlet.http.HttpServletResponse;  
  18.   
  19.    
  20.   
  21. public class AsyncProcessServlet extends HttpServlet{  
  22.   
  23.    
  24.   
  25. /** 
  26.  
  27. *  3.0异步调用在servlet线程内使用另一个异步线程来调用业务模块,容器线程直接返回,属于非阻塞式 
  28.  
  29. */  
  30.   
  31. private static final long serialVersionUID = 1L;  
  32.   
  33. public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{  
  34.   
  35. AsyncContext ctx = request.startAsync();  
  36.   
  37. new Thread(new Executor(ctx)).start();  
  38.   
  39. }  
  40.   
  41. }  
  42.   
  43.   
  44. package servlets;  
  45.   
  46.    
  47.   
  48. import java.io.IOException;  
  49.   
  50. import java.io.PrintWriter;  
  51.   
  52.    
  53.   
  54. import javax.servlet.AsyncContext;  
  55.   
  56. import javax.servlet.http.HttpServletResponse;  
  57.   
  58.    
  59.   
  60. public class Executor implements Runnable{  
  61.   
  62. private AsyncContext ctx;  
  63.   
  64. public Executor(AsyncContext ctx){  
  65.   
  66. this.ctx = ctx;  
  67.   
  68. }  
  69.   
  70. public void run() {  
  71.   
  72. try {  
  73.   
  74. Thread.sleep(200);  
  75.   
  76. catch (InterruptedException e1) {  
  77.   
  78. e1.printStackTrace();  
  79.   
  80. }  
  81.   
  82. HttpServletResponse res = (HttpServletResponse)this.ctx.getResponse();  
  83.   
  84. res.setContentType("text/html");  
  85.   
  86. PrintWriter out = null;  
  87.   
  88. try {  
  89.   
  90. out = res.getWriter();  
  91.   
  92. catch (IOException e) {  
  93.   
  94. e.printStackTrace();  
  95.   
  96. }  
  97.   
  98. out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">");  
  99.   
  100. out.println("<html>");  
  101.   
  102. out.println("Hello,World!");  
  103.   
  104. out.println("</html>");  
  105.   
  106. this.ctx.complete();  
  107.   
  108. }  
  109.   
  110. }  


压力测试结果(见附件):


传统方式,700并发:失败0%



传统方式,800并发:失败2.5%



传统方式,1000并发:失败16%



3.0异步方式,900并发:失败0%



3.0异步方式,1000并发:失败0%



3.0异步方式,1100并发:失败0%



后记,对于性能调试而言,要具体应用甚至具体交易具体分析。不能说一定是异步方式要优于同步处理方式,异步方式优势在于其非阻塞式的处理能够更有 效的利用容器线程,提供吞吐能力,但是其在业务处理的过程中多启用了更多的线程,从而加大了线程切换时CPU的开销,对于CPU消耗型的应用或交易而言, 异步方式便不是一个好的解决方案。所以对于性能问题,要找到当前影响性能的主要瓶颈,针对具体的问题采用不同的解决方案。

你可能感兴趣的:(servlet)