Netflix Zuul與Nginx的性能對比

這是一篇翻譯,關於大家經常質疑的一個問題:API網關Zuul的性能。

原文:NETFLIX ZUUL VS NGINX PERFORMANCE

作者:STANISLAV MIKLIK

如今你可以聽到很多關於「微服務」的信息。Spring Boot是一個用來構建單個微服務應用的理想選擇,但是你還需要以某種方式將它們互相聯繫起來。這就是Spring Cloud試圖解決的問題,尤其是Spring Cloud Netflix。它提供了各種組件,比如:Eureka服務發現與Ribbon客戶端負載均衡的結合,為內部「微服務」提供通信支持。但是,如果你想要與外界通信時(你提供外部API,或只是從你的頁面使用AJAX),將各種服務隱藏在一個代理之後是一個明智的選擇。

常規的選擇我們會使用Nginx作為代理。但是Netflix帶來了它自己的解決方案——智能路由Zuul。它帶有許多有趣的功能,它可以用於身份驗證、服務遷移、分級卸載以及各種動態路由選項。同時,它是使用Java編寫的。如果Netflix使用它,那麼它與本地反向代理相比是否足夠快呢?或者當我們對靈活性(或其他功能)要求更高時,它是否適合與Nginx聯合使用。

免責聲明:不要認為這是一個嚴肅的基準。我只是想感受Nginx和Zuul的差異,因為我在互聯網上並沒有找到任何基準(也可能是我沒有搜索足夠長的時間)。它不遵循任何推薦的基準測試方法(預熱時間、測試次數……),我只是使用3個在不同可用區域的EC2實例(這不是最佳的)。

測試

那我做了什麼呢?測試是比較兩種解決方案的原始性能,沒有任何其他特殊的功能。我只是同時發起單個HTTP請求來獲取一個HTML頁面(大小約為26KB)。我使用ApacheBench來發起200個並發線程的測試(我也嘗試了httpperf,但是它需要更高的CPU要求,所以還是選擇了要求更低的ab)。

直接連接

首先,我感興趣的是不通過任何反向代理直接訪問HTTP伺服器的性能。Ab在一台機器上運行,直接訪問目標伺服器。

$ ab -n 10000 -c 200 http://target/sample.htmln....nDocument Path: /sample.htmlnDocument Length: 26650 bytesnTotal transferred: 268940000 bytesnHTML transferred: 266500000 bytesnRequests per second: 2928.45 [#/sec] (mean)nTime per request: 68.295 [ms] (mean)nTime per request: 0.341 [ms] (mean, across all concurrent requests)nTransfer rate: 76911.96 [Kbytes/sec] receivednConnection Times (ms)n min mean[+/-sd] median maxnConnect: 4 33 6.0 32 66nProcessing: 20 35 7.5 35 392nWaiting: 20 35 6.4 34 266nTotal: 24 68 7.8 66 423nPercentage of the requests served within a certain time (ms)n 50% 66n 66% 67n 75% 69n 80% 70n 90% 74n 95% 81n 98% 91n 99% 92n 100% 423 (longest request)n

很好,幾次測試都顯示了類似的值:2928、2725、2834、2648 req/s。有一些偏差,但這些數字現在還不重要。

通過Nginx

現在我可以使用Nginx的代理服務。只需要將Nginx配置更新為代理到目標伺服器,比如:

server {n listen 80 default_server;n listen [::]:80 default_server ipv6only=on;n # Make site accessible from http://localhost/n server_name localhost;n # allow file uploadn client_max_body_size 10M;n location / {n proxy_set_header X-Real-IP $remote_addr;n proxy_set_header X-Forwarded-For $remote_addr;n proxy_set_header Host $host;n proxy_pass http://target:80;n }n}n

像之前一樣運行類型的測試:

$ ab -n 50000 -c 200 http://proxy/sample.htmln...nServer Software: nginx/1.4.6nServer Hostname: proxynServer Port: 80nDocument Path: /sample.htmlnDocument Length: 26650 bytesnConcurrency Level: 200nTime taken for tests: 52.366 secondsnComplete requests: 50000nFailed requests: 0nTotal transferred: 1344700000 bytesnHTML transferred: 1332500000 bytesnRequests per second: 954.81 [#/sec] (mean)nTime per request: 209.465 [ms] (mean)nTime per request: 1.047 [ms] (mean, across all concurrent requests)nTransfer rate: 25076.93 [Kbytes/sec] receivednConnection Times (ms)n min mean[+/-sd] median maxnConnect: 3 50 11.7 48 114nProcessing: 37 159 11.9 160 208nWaiting: 36 159 11.9 160 207nTotal: 40 209 10.4 209 256nPercentage of the requests served within a certain time (ms)n 50% 209n 66% 212n 75% 214n 80% 216n 90% 220n 95% 224n 98% 232n 99% 238n 100% 256 (longest request)n

測試結果為954、954、941 req/s。性能與延遲(如預期)變差了。

通過Zuul

現在我們在同一台機器上安裝Zuul。它的應用本身很簡單:

@SpringBootApplicationn@Controllern@EnableZuulProxynpublic class DemoApplication {n public static void main(String[] args) {n new SpringApplicationBuilder(DemoApplication.class)n .web(true).run(args);n }n}n

我們還需要在 application.yml中定義固定的路由規則:

zuul:n routes:n sodik:n path: /sodik/**n url: http://targetn

現在我們試試運行測試:

$ ab -n 50000 -c 200 http://proxy:8080/sodik/sample.htmlnServer Software: Apache-Coyote/1.1nServer Hostname: proxynServer Port: 8080nDocument Path: /sodik/sample.htmlnDocument Length: 26650 bytesnConcurrency Level: 200nTime taken for tests: 136.164 secondsnComplete requests: 50000nFailed requests: 2n(Connect: 0, Receive: 0, Length: 2, Exceptions: 0)nNon-2xx responses: 2nTotal transferred: 1343497042 bytesnHTML transferred: 1332447082 bytesnRequests per second: 367.20 [#/sec] (mean)nTime per request: 544.657 [ms] (mean)nTime per request: 2.723 [ms] (mean, across all concurrent requests)nTransfer rate: 9635.48 [Kbytes/sec] receivednConnection Times (ms)nmin mean[+/-sd] median maxnConnect: 2 12 92.3 2 1010nProcessing: 15 532 321.6 461 10250nWaiting: 10 505 297.2 441 9851nTotal: 17 544 333.1 467 10270nPercentage of the requests served within a certain time (ms)n50% 467n66% 553n75% 626n80% 684n90% 896n95% 1163n98% 1531n99% 1864n100% 10270 (longest request)n n

結果比我(樂觀的)猜測更差。此外,我們還能看到兩次請求失敗(我們可以在Zuul的日誌中看到有兩個相應的異常,這些異常引發了HTTP連接池超時)。顯然默認情況下超時時間為10秒。

我們再進一步測試,得到了更多的結果:

Document Path: /sodik/sample.htmlnDocument Length: 26650 bytesnConcurrency Level: 200nTime taken for tests: 50.080 secondsnComplete requests: 50000nFailed requests: 0nTotal transferred: 1343550000 bytesnHTML transferred: 1332500000 bytesnRequests per second: 998.39 [#/sec] (mean)nTime per request: 200.322 [ms] (mean)nTime per request: 1.002 [ms] (mean, across all concurrent requests)nTransfer rate: 26199.09 [Kbytes/sec] receivednConnection Times (ms)nmin mean[+/-sd] median maxnConnect: 2 16 7.9 16 126nProcessing: 15 184 108.1 203 1943nWaiting: 13 183 105.9 202 1934nTotal: 18 200 107.8 218 1983nPercentage of the requests served within a certain time (ms)n50% 218n66% 228n75% 235n80% 239n90% 254n95% 287n98% 405n99% 450n100% 1983 (longest request)n

哇,不錯的改善。我認為Java JIT編譯對於性能有一定的幫助,但是要驗證這是否只是一個巧合,再嘗試一次:1010 req / sec。最終結果對我來說是一個驚喜。

結論

Zuul的原始性能非常接近於Nginx。事實上,在啟動預熱之後,我的測試結果甚至略好一些(重申免責聲明-這並非一個嚴肅的基準性能測試)。Nginx顯示出更多的可預測性能(變化較小),可悲的是在Zuul預熱期間,我們經歷了一些小故障(150000個請求中的2個,但是您的微服務應該是容錯機制的,對吧?)。

所以,如果您考慮使用一些Zuul的額外功能,或者希望通過它與其他Netflix服務集成(比如Eureka)獲得更多的服務能力,Zuul看起來非常有希望作為簡單反向代理的替代產品。也許這也是Netflix使用的原因,所以您也可以嘗試一下。

推薦閱讀:

【spring指南系列】使用Redis進行消息傳遞
springcloud: 配置中心svn示例和refresh
Spring MVC中使用Thymeleaf模板引擎
史上最簡單的SpringCloud教程 | 第二篇:服務消費者(rest + ribbon)

TAG:Spring | SpringCloud |