Netflix Zuul與Nginx的性能對比
如今你可以聽到很多關(guān)于“微服務(wù)”的信息。Spring Boot是一個用來構(gòu)建單個微服務(wù)應(yīng)用的理想選擇,但是你還需要以某種方式將它們互相聯(lián)系起來。這就是Spring Cloud試圖解決的問題,尤其是Spring Cloud Netflix。它提供了各種組件,比如:Eureka服務(wù)發(fā)現(xiàn)與Ribbon客戶端負載均衡的結(jié)合,為內(nèi)部“微服務(wù)”提供通信支持。但是,如果你想要與外界通信時(你提供外部API,或只是從你的頁面使用AJAX),將各種服務(wù)隱藏在一個代理之后是一個明智的選擇。
常規(guī)的選擇我們會使用Nginx作為代理。但是Netflix帶來了它自己的解決方案——智能路由Zuul。它帶有許多有趣的功能,它可以用于身份驗證、服務(wù)遷移、分級卸載以及各種動態(tài)路由選項。同時,它是使用Java編寫的。如果Netflix使用它,那么它與本地反向代理相比是否足夠快呢?或者當我們對靈活性(或其他功能)要求更高時,它是否適合與Nginx聯(lián)合使用。
免責(zé)聲明:不要認為這是一個嚴肅的基準。我只是想感受Nginx和Zuul的差異,因為我在互聯(lián)網(wǎng)上并沒有找到任何基準(也可能是我沒有搜索足夠長的時間)。它不遵循任何推薦的基準測試方法(預(yù)熱時間、測試次數(shù)……),我只是使用3個在不同可用區(qū)域的EC2實例(這不是***的)。
測試
那我做了什么呢?測試是比較兩種解決方案的原始性能,沒有任何其他特殊的功能。我只是同時發(fā)起單個HTTP請求來獲取一個HTML頁面(大小約為26KB)。我使用ApacheBench來發(fā)起200個并發(fā)線程的測試(我也嘗試了httpperf,但是它需要更高的CPU要求,所以還是選擇了要求更低的ab)。
直接連接
首先,我感興趣的是不通過任何反向代理直接訪問HTTP服務(wù)器的性能。Ab在一臺機器上運行,直接訪問目標服務(wù)器。
- $ ab -n 10000 -c 200 http://target/sample.html
- ....
- Document Path: /sample.html
- Document Length: 26650 bytes
- Total transferred: 268940000 bytes
- HTML transferred: 266500000 bytes
- Requests per second: 2928.45 [#/sec] (mean)
- Time per request: 68.295 [ms] (mean)
- Time per request: 0.341 [ms] (mean, across all concurrent requests)
- Transfer rate: 76911.96 [Kbytes/sec] received
- Connection Times (ms)
- min mean[+/-sd] median max
- Connect: 4 33 6.0 32 66
- Processing: 20 35 7.5 35 392
- Waiting: 20 35 6.4 34 266
- Total: 24 68 7.8 66 423
- Percentage of the requests served within a certain time (ms)
- 50% 66
- 66% 67
- 75% 69
- 80% 70
- 90% 74
- 95% 81
- 98% 91
- 99% 92
- 100% 423 (longest request)
很好,幾次測試都顯示了類似的值:2928、2725、2834、2648 req/s。有一些偏差,但這些數(shù)字現(xiàn)在還不重要。
通過Nginx
現(xiàn)在我可以使用Nginx的代理服務(wù)。只需要將Nginx配置更新為代理到目標服務(wù)器,比如:
- server {
- listen 80 default_server;
- listen [::]:80 default_server ipv6only=on;
- # Make site accessible from http://localhost/
- server_name localhost;
- # allow file upload
- client_max_body_size 10M;
- location / {
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $remote_addr;
- proxy_set_header Host $host;
- proxy_pass http://target:80;
- }
- }
像之前一樣運行類型的測試:
- $ ab -n 50000 -c 200 http://proxy/sample.html
- ...
- Server Software: nginx/1.4.6
- Server Hostname: proxy
- Server Port: 80
- Document Path: /sample.html
- Document Length: 26650 bytes
- Concurrency Level: 200
- Time taken for tests: 52.366 seconds
- Complete requests: 50000
- Failed requests: 0
- Total transferred: 1344700000 bytes
- HTML transferred: 1332500000 bytes
- Requests per second: 954.81 [#/sec] (mean)
- Time per request: 209.465 [ms] (mean)
- Time per request: 1.047 [ms] (mean, across all concurrent requests)
- Transfer rate: 25076.93 [Kbytes/sec] received
- Connection Times (ms)
- min mean[+/-sd] median max
- Connect: 3 50 11.7 48 114
- Processing: 37 159 11.9 160 208
- Waiting: 36 159 11.9 160 207
- Total: 40 209 10.4 209 256
- Percentage of the requests served within a certain time (ms)
- 50% 209
- 66% 212
- 75% 214
- 80% 216
- 90% 220
- 95% 224
- 98% 232
- 99% 238
- 100% 256 (longest request)
測試結(jié)果為954、954、941 req/s。性能與延遲(如預(yù)期)變差了。
通過Zuul
現(xiàn)在我們在同一臺機器上安裝Zuul。它的應(yīng)用本身很簡單:
- @SpringBootApplication
- @Controller
- @EnableZuulProxy
- public class DemoApplication {
- public static void main(String[] args) {
- new SpringApplicationBuilder(DemoApplication.class)
- .web(true).run(args);
- }
- }
我們還需要在 application.yml中定義固定的路由規(guī)則:
- zuul:
- routes:
- sodik:
- path: /sodik/**
- url: http://target
現(xiàn)在我們試試運行測試:
- $ ab -n 50000 -c 200 http://proxy:8080/sodik/sample.html
- Server Software: Apache-Coyote/1.1
- Server Hostname: proxy
- Server Port: 8080
- Document Path: /sodik/sample.html
- Document Length: 26650 bytes
- Concurrency Level: 200
- Time taken for tests: 136.164 seconds
- Complete requests: 50000
- Failed requests: 2
- (Connect: 0, Receive: 0, Length: 2, Exceptions: 0)
- Non-2xx responses: 2
- Total transferred: 1343497042 bytes
- HTML transferred: 1332447082 bytes
- Requests per second: 367.20 [#/sec] (mean)
- Time per request: 544.657 [ms] (mean)
- Time per request: 2.723 [ms] (mean, across all concurrent requests)
- Transfer rate: 9635.48 [Kbytes/sec] received
- Connection Times (ms)
- min mean[+/-sd] median max
- Connect: 2 12 92.3 2 1010
- Processing: 15 532 321.6 461 10250
- Waiting: 10 505 297.2 441 9851
- Total: 17 544 333.1 467 10270
- Percentage of the requests served within a certain time (ms)
- 50% 467
- 66% 553
- 75% 626
- 80% 684
- 90% 896
- 95% 1163
- 98% 1531
- 99% 1864
- 100% 10270 (longest request)
結(jié)果比我(樂觀的)猜測更差。此外,我們還能看到兩次請求失敗(我們可以在Zuul的日志中看到有兩個相應(yīng)的異常,這些異常引發(fā)了HTTP連接池超時)。顯然默認情況下超時時間為10秒。
我們再進一步測試,得到了更多的結(jié)果:
- Document Path: /sodik/sample.html
- Document Length: 26650 bytes
- Concurrency Level: 200
- Time taken for tests: 50.080 seconds
- Complete requests: 50000
- Failed requests: 0
- Total transferred: 1343550000 bytes
- HTML transferred: 1332500000 bytes
- Requests per second: 998.39 [#/sec] (mean)
- Time per request: 200.322 [ms] (mean)
- Time per request: 1.002 [ms] (mean, across all concurrent requests)
- Transfer rate: 26199.09 [Kbytes/sec] received
- Connection Times (ms)
- min mean[+/-sd] median max
- Connect: 2 16 7.9 16 126
- Processing: 15 184 108.1 203 1943
- Waiting: 13 183 105.9 202 1934
- Total: 18 200 107.8 218 1983
- Percentage of the requests served within a certain time (ms)
- 50% 218
- 66% 228
- 75% 235
- 80% 239
- 90% 254
- 95% 287
- 98% 405
- 99% 450
- 100% 1983 (longest request)
哇,不錯的改善。我認為Java JIT編譯對于性能有一定的幫助,但是要驗證這是否只是一個巧合,再嘗試一次:1010 req / sec。最終結(jié)果對我來說是一個驚喜。
結(jié)論
Zuul的原始性能非常接近于Nginx。事實上,在啟動預(yù)熱之后,我的測試結(jié)果甚至略好一些(重申免責(zé)聲明-這并非一個嚴肅的基準性能測試)。Nginx顯示出更多的可預(yù)測性能(變化較小),可悲的是在Zuul預(yù)熱期間,我們經(jīng)歷了一些小故障(150000個請求中的2個,但是您的微服務(wù)應(yīng)該是容錯機制的,對吧?)。
所以,如果您考慮使用一些Zuul的額外功能,或者希望通過它與其他Netflix服務(wù)集成(比如Eureka)獲得更多的服務(wù)能力,Zuul看起來非常有希望作為簡單反向代理的替代產(chǎn)品。也許這也是Netflix使用的原因,所以您也可以嘗試一下。
【本文為51CTO專欄作者“翟永超”的原創(chuàng)稿件,轉(zhuǎn)載請通過51CTO聯(lián)系作者獲取授權(quán)】