2015年4月18日 星期六

Java Servlet Container Performance Tesing (1)


最近實在好忙啊,都沒時間寫Blog...而且公司好多大大壓力真大~XD

不過我放上面那張圖並不是說我一秒鐘幾十萬上下所以很忙,而是我新接觸的產業對於系統效能是很講究,因為真的是一秒鐘幾十萬上下~:P

以前可以偷懶只要求功能有做出來就好,效能不要太差就好,但是現在的產品對於系統反應速度(Response time )可以說是錙銖必較,所以想盡辦法都得從每個地方榨出效能。

通常一個系統效能可以調教的部分主要有三個部分:OS, Web Server, DB,最近我就先從最基本的Web端著手。



最近看到這個投影片,裡面也講到,不要偷懶上網看人家stackoverflow 的文章就直接下結論什麼東西比較好,也不要直接抄別人的參數,因為每個應用的情境不同,可以調教的參數和選擇的點也會差很多,而且網路上很多測試評比也有很多可議之處,還是自己來比較準,參考 Lies, Damned Lies and Benchmarks



所以那就只好捲起袖子來自己動手做實驗,我得實驗方法也很間單,以Spring boot 為基礎,然後抽換Embedded Web Container來測試,主要測試對象Jetty和Tomcat。

我的測試專案:Servlet Container Test 
 
Jetty 是以NIO為基礎的Container ,從第九版之後做了大幅度的架構重整,號稱效能很威,然後調教的部分可以參考他官網wiki:Optimizing Jetty  (雖然沒啥內容....)

可是Tomcat 就沒那麼簡單了,他光是Connector就有好幾種,對於系統效能影響有很大,主要分為以下幾種:

1. [BIO]   Http11Protocol  (BIO 就是 Blocking I/O 縮寫)
2. [NIO]   Http11NioProtocol
3. [NIO2] Http11Nio2Protocol (tomcat 8以後推出)
4. [APR]  Http11AprProtocol (Native implement)

詳細資料可以參考官方文件:Connector Comparison


如果要使用APR 就必須先安裝Native Lib 比較麻煩,可以參考這篇 CentOS: Installing Apache Portable Runtime (APR) for Tomcat

測試系統Azure A2 機器


簡單的測試指令: ab -n 1000000 -c 300

Tomcat 8 BIO

Requests per second:    2602.83 [#/sec] (mean)
Time per request:       115.259 [ms] (mean)
Time per request:       0.384 [ms] (mean, across all concurrent requests)
Transfer rate:          538.87 [Kbytes/sec] received

Connection Times (ms)
                    min  mean[+/-sd] median   max
Connect:         1   65     316.2         1    15196
Processing:     2   50       54.2      36      8608
Waiting:           2   47       51.6      35      8608
Total:               3  115     324.1      38    15316

Percentage of the requests served within a certain time (ms)
  50%     38
  66%     48
  75%     58
  80%     66
  90%    117
  95%   1032
  98%   1066
  99%   1115
 100%  15316 (longest request)


tomcat 8 apr

Requests per second:    2657.37 [#/sec] (mean)
Time per request:       112.893 [ms] (mean)
Time per request:       0.376 [ms] (mean, across all concurrent requests)
Transfer rate:          550.16 [Kbytes/sec] received

Connection Times (ms)
                     min  mean[+/-sd] median   max
Connect:          1   55     240.8       3      7123
Processing:     2   58      145.5     40      8087
Waiting:           1   38        53.5     27      3752
Total:               3  113     287.3     45      8986

Percentage of the requests served within a certain time (ms)
  50%     45
  66%     56
  75%     67
  80%     77
  90%    142
  95%    570
  98%   1067
  99%   1102
 100%   8986 (longest request)


tomcat 8 nio2

Requests per second:    2658.73 [#/sec] (mean)
Time per request:       112.836 [ms] (mean)
Time per request:       0.376 [ms] (mean, across all concurrent requests)
Transfer rate:          550.44 [Kbytes/sec] received

Connection Times (ms)
                     min  mean[+/-sd] median   max
Connect:         1   63     300.5      1       15148
Processing:     1   49      50.0     35        3198
Waiting:           1   46      46.0     34        3197
Total:               2  113   307.6      37      15200

Percentage of the requests served within a certain time (ms)
  50%     37
  66%     47
  75%     56
  80%     65
  90%    122
  95%   1030
  98%   1064
  99%   1107
 100%  15200 (longest request)

jetty 9

Requests per second:    2829.32 [#/sec] (mean)
Time per request:       106.033 [ms] (mean)
Time per request:       0.353 [ms] (mean, across all concurrent requests)
Transfer rate:          549.84 [Kbytes/sec] received

Connection Times (ms)
                     min  mean[+/-sd] median   max
Connect:         1   72      328.7      1    15158
Processing:     2   34       37.9     24     4125
Waiting:           1   34       37.8     24     4125
Total:               3  106     333.1    27    15388

Percentage of the requests served within a certain time (ms)
  50%     27
  66%     35
  75%     42
  80%     49
  90%     86
  95%   1026
  98%   1055
  99%   1091
 100%  15388 (longest request)


從RPS來看 jetty 9 > tomcat NIO2 ~ tomcat APR < tomcat BIO
不過說實在也差不了多少(何苦這樣比較呢~~開始自暴自棄)
此外nio 的在worst case 都會炸裂,打回跟BIO差不多程度?

這就結束了嗎? 不...

在許多Production 環境的架構通常會在Servlet Container 前面放台Proxy(Apache or Nginx),這時候故事又可能不一樣了...

將會有以下案例:

1. Apache (mod_proxy) <---->Jetty 9
2. Nginx    (mod_proxy) <---> Jetty 9 [註1]
3. Apache (mod_proxy_ajp) <----> tomcat 8 + AjpNioProtocol (NIO)
4. Apache (mod_proxy_ajp) <----> tomcat 8 + AjpAprProtocol (APR)
5. Nginx (mod_proxy_ajp) <----> tomcat 8 + AjpNioProtocol (NIO)
6. Nignx (mod_proxy_ajp) <----> tomcat 8 + AjpAprProtocol (APR)[註2]
5. Nginx (mod_proxy) <----> tomcat 8 + NioProtocol (NIO)
6. Nignx (mod_proxy) <----> tomcat 8 + AprProtocol (APR)

[註1] Jetty 本身不建議使用AJP 
[註2] Nginx 本身沒有提供AJP module 只有3rd-party 所以效能和穩定度待確認


這麼多排列組合看了就累了....XDrz....

Referenc:

[1] NIO 2 in Apache Tomcat 8

[2] Tomcat 8(十)HTTP/AJP Connector、Bio/Nio/Apr性能对比

[3] How to Optimize Tomcat Performance

[4]  Planning for High Concurrency Load Tests with JMeter
張貼留言