微服務架構:Zuul 1.0 和 2.0 我們該如何選擇?
作者:架構師楊波
來源:波波微課
在今年5月中,Netflix終於開源了它的支援非同步呼叫模式的Zuul閘道器2.0版本,真可謂千呼萬喚始出來。從Netflix的官方博文[附錄1]中,我們獲得的資訊也比較令人振奮:
The Cloud Gateway team at Netflix runs and operates more than 80 clusters of Zuul 2, sending traffic to about 100 (and growing) backend service clusters which amounts to more than 1 million requests per second. Netflix部署了超過80+的Zuul2雲網關叢集,流量經過Zuul2叢集被路由到後端超過100+的微服務,且每秒鐘經過Zuul2叢集的請求超過100萬。
Zuul2看起來很強大,支援非同步高併發(Zuul1僅支援同步)特性看起來很亮眼,那麼我們是否就應該拋棄Zuul1,開始擁抱Zuul2呢?作為架構師,我們不能盲目追時髦,技術的選擇必須基於實踐和理性的分析,基於我之前對Zuul1的一線落地實戰經驗,也基於我近期對Zuul2的一些調研,我會在本文中對Zuul1和Zuul2做一個比較客觀的程式設計模型和優劣分析,同時給出我的個人建議。
Zuul 1.0程式設計模型和優劣
Zuul1設計比較簡單,程式碼不多也比較容易讀懂,它本質上就是一個同步Servlet,採用多執行緒阻塞模型,如上圖所示[圖片來自附錄4]。
同步Servlet使用thread per connection方式處理請求。簡單講,每來一個請求,Servlet容器要為該請求分配一個執行緒專門負責處理這個請求,直到響應返回客戶端這個執行緒才會被釋放返回容器執行緒池。如果後臺服務呼叫比較耗時,那麼這個執行緒就會被阻塞,阻塞期間執行緒資源被佔用,不能幹其它事情。我們知道Servlet容器執行緒池的大小是有限制的,當前端請求量大,而後臺慢服務比較多時,很容易耗盡容器執行緒池內的執行緒,造成容器無法接受新的請求,Netflix為此還專門研發了Hystrix[附錄2]熔斷元件來解決慢服務耗盡資源問題。
注意在上圖Netflix給出的場景中,它的後臺服務呼叫也是啟動另外一個IO執行緒來處理的,但是本質上還是阻塞模式,後臺IO執行緒在處理的時候,前臺容器執行緒仍然是阻塞的。
同步阻塞模式有利有弊,分析如下圖:
優勢
同步阻塞模式的程式設計模型比較簡單,整個請求->處理->響應的流程(call flow)都是在一個執行緒中處理的,這樣開發除錯比較方便易於理解,比如出了問題跟蹤除錯比較方便。另外,執行緒區域性變數(ThreadLocal)機制在同步多執行緒模式下可以工作,有些監控產品,例如CAT呼叫鏈依賴於ThreadLocal,在同步多執行緒模式下,CAT埋點比較方便,呼叫鏈關係的展示也比較直觀。
不足
我們知道執行緒本身需要消耗CPU和記憶體資源,且多執行緒之間切換是有開銷的(所謂的上下文切換Context Switch開銷),執行緒越多,這種上下文切換的開銷就越大,同步阻塞模式一般會啟動很多的執行緒,必然引入執行緒切換開銷。另外,同步阻塞模式下,容器執行緒池的數量一般是固定的,造成對連線數有一定限制,當後臺服務慢,容器執行緒池易被耗盡,一旦耗盡容器會拒絕新的請求,這個時候容器執行緒其實並不忙,只是被後臺服務呼叫IO阻塞,但是幹不了其它事情。
總體上,同步阻塞模式比較適用於計算密集型(CPU bound)應用場景。對於IO密集型場景(IO bound),同步阻塞模式會白白消耗很多執行緒資源,它們都在等待IO的阻塞狀態,沒有做實質性工作。
Zuul 2.0程式設計模型和優劣
Zuul2的設計相對比較複雜,程式碼也不太容易讀懂,它採用了Netty實現非同步非阻塞程式設計模型,如上圖所示[圖片來自附錄4]。
一般非同步模式的本質都是使用佇列Queue(或稱匯流排Bus),在上圖中,你可以簡單理解為前端有一個佇列專門負責處理使用者請求,後端有個佇列專門負責處理後臺服務呼叫,中間有個事件環執行緒(Event Loop Thread),它同時監聽前後兩個佇列上的事件,有事件就觸發回撥函式處理事件。這種模式下需要的執行緒比較少,基本上每個CPU核上只需要一個事件環處理執行緒,前端的連線數可以很多,連線來了只需要進佇列,不需要啟動執行緒,事件環執行緒由事件觸發,沒有多執行緒阻塞問題。
非同步非阻塞模式也是有利有弊,分析如下圖:
優勢
非同步非阻塞模式啟動的執行緒很少,基本上一個CPU core上只需啟一個事件環處理執行緒,它使用的執行緒資源就很少,上下文切換(Context Switch)開銷也少。非阻塞模式可以接受的連線數大大增加,可以簡單理解為請求來了只需要進佇列,這個佇列的容量可以設得很大,只要不超時,佇列中的請求都會被依次處理。
不足
非同步模式讓程式設計模型變得複雜。一方面Zuul2本身的程式碼要比Zuul1複雜很多,Zuul1的程式碼比較容易看懂,Zuul2的程式碼看起來就比較費勁。另一方面非同步模型沒有一個明確清晰的請求->處理->響應執行流程(call flow),它的流程是通過事件觸發的,請求處理的流程隨時可能被切換斷開,內部實現要通過一些關聯id機制才能把整個執行流再串聯起來,這就給開發除錯運維引入了很多複雜性,比如你在IDE裡頭除錯非同步請求流就非常困難。另外ThreadLocal機制在這種非同步模式下就不能簡單工作,因為只有一個事件環執行緒,不是每個請求一個執行緒,也就沒有執行緒區域性的概念,所以對於CAT這種依賴於ThreadLocal才能工作的監控工具,呼叫鏈埋點就不好搞(實際可以工作但需要進行特殊處理)。
總體上,非同步非阻塞模式比較適用於IO密集型(IO bound)場景,這種場景下系統大部分時間在處理IO,CPU計算比較輕,少量事件環執行緒就能處理。
Zuul1和Zuul2的效能比對
Netflix本身對閘道器使用非同步非阻塞模式這件事情是非常謹慎的,它們進行了嚴格的效能測試,下面是Netflix給出的一些效能資料,來自Zuul2閘道器核心研發成員Arthur Gonigberg的ppt(Zuul's Journey to Non-Blocking)[附錄3]:
Netflix給出了一個比較模糊的資料,大致Zuul2的效能比Zuul1好20%左右,這裡的效能主要指每節點每秒處理的請求數。為什麼說模糊呢?因為這個資料受實際測試環境,流量場景模式等眾多因素影響,你很難復現這個測試資料。即便這個20%的效能提升是確實的,其實這個效能提升也並不大,和非同步引入的複雜性相比,這20%的提升是否值得是個問題。Netflix本身在其博文[附錄4]和ppt[附錄3]中也是有點含糊其詞,甚至自身都有一些疑問的。
While we did not see a significant efficiency benefit in migrating to async and non-blocking, we did achieve the goals of connection scaling.
比較明確的是,Zuul2在連線數方面表現要好於Zuul1,也就是說Zuul2能接受更多的連線數。
Zuul 2.0架構和額外特性
上圖是Zuul2的架構,和Zuul1沒有本質區別,兩點變化:
前端用Netty Server代替Servlet,目的是支援前端非同步。後端用Netty Client代替Http Client,目的是支援後端非同步。
過濾器換了一下名字,用Inbound Filters代替Pre-routing Filters,用Endpoint Filter代替Routing Filter,用Outbound Filters代替Post-routing Filters。
上圖是Zuul2的一些功能亮點,我個人認為除了對HTTP/2的支援算是一個亮點,其它都是在安全、彈性和運維層面的一些優化,不能算新功能。其中像Request Passport,Status Categories,Request Attempts這些所謂的新功能,其實是為了減輕非同步帶來的複雜性,方便開發人員除錯非同步請求而專門開發的。
建議
基於上述分析,我對大家的建議是在生產環境中繼續使用Zuul1,原因如下:
Zuul1同步程式設計模型簡單,門檻低,開發運維方便,容易除錯定位問題。Zuul2門檻高,除錯不方便。
Zuul1監控埋點容易,比如和呼叫鏈監控工具CAT整合,如果你用Zuul2的話,CAT不好埋點是個問題。
Zuul1已經開源超過6年,穩定成熟,坑已經被踩平。Zuul2剛開源很新,實際落地案例不多,難說有bug需要踩坑。
大部分公司達不到Netflix那個量級,Netflix是要應對每日千億級流量,它們才挖空心思搞非同步,一般公司億級可能都不到,Zuul1綽綽有餘。
Zuul1可以整合Hystrix熔斷元件,可以部分解決後臺服務慢阻塞閘道器執行緒的問題。
Zuul1可以使用Servlet 3.0規範支援的AsyncServlet進行優化,可以實現前端非同步,支援更多的連線數,達到和Zuul2一樣的效果,但是不用引入太多非同步複雜性。波波和極客時間合作的課程《微服務架構和實踐160講》,7月份馬上上線第三模組《微服務閘道器Zuul架構和實踐》,其中會講解Zuul1如何使用AsyncServlet優化連線數,歡迎大家關注。
對於Zuul2,我的建議是持謹慎觀望的態度,可以在測試環境小規模實驗驗證,但是暫不上到生產環境。
結論
同步非同步各有利弊,同步多執行緒程式設計模型簡單,但會有執行緒開銷和阻塞問題,非同步非阻塞模式執行緒少併發高,但是程式設計模型變得複雜。
架構師做技術選型需要嚴謹務實,具備批判性思維(Critical Thinking),即使是對於一線大公司推出的開源產品,也要批判性看待,不可盲目追新。
個人建議生產環境繼續使用Zuul1,同步阻塞模式的一些不足,可以使用熔斷元件Hystrix和AsyncServlet等技術進行優化。波波和極客時間合作的課程《微服務架構和實踐160講》,7月份馬上上線第三模組《微服務閘道器Zuul架構和實踐》,其中會講解對Zuul1的這些優化技術,歡迎大家關注。
附錄
Open Sourcing Zuul 2 https://medium.com/netflix-techblog/open-sourcing-zuul-2-82ea476cb2b3
Hystrix https://github.com/netflix/hystrix
Zuul's Journey to Non-Blocking https://github.com/strangeloop/StrangeLoop2017/blob/master/slides/ArthurGonigberg-ZuulsJourneyToNonBlocking.pdf
Zuul2:Netflix's Journey to Asynchronous,Non-blocking Systems https://medium.com/netflix-techblog/zuul-2-the-netflix-journey-to-asynchronous-non-blocking-systems-45947377fb5c
- END -
往期推薦:
死磕Java系列:
……
Spring系列:
……
可關注我的公眾號
深入交流、更多福利
掃碼加入我的知識星球
點選“閱讀原文”,看本號其他精彩內容
相關推薦
微服務架構:Zuul 1.0 和 2.0 我們該如何選擇?
作者:架構師楊波來源:波波微課在今年5月中,Netflix終於開源了它的支援非同步呼叫模式的Zu
Re:從0開始的微服務架構:(一)重識微服務架構--轉
相關 推廣 模塊劃分 ati 滿足 face jar 點擊放大 積累 原文地址:http://www.infoq.com/cn/articles/micro-service-architecture-from-zero?utm_source=infoq&utm_me
從0開始的微服務架構:(一)重識微服務架構
拆分 dock try 快速入門 比較 資源 貼吧 升級維護 頁面 導語 雖然已經紅了很久,但是“微服務架構”正變得越來越重要,也將繼續火下去。 各個公司與技術人員都在分享微服務架構的相關知識與實踐經驗,但我們發現,目前網上的這些相關文章中,要麽上來就是很有借鑒意義的幹貨,
從0開始的微服務架構:(二)如何快速體驗微服務架構?
常常 原來 人員 google tty 打包 第三方 江湖 ces 雖然已經紅了很久,但是“微服務架構”正變得越來越重要,也將繼續火下去。各個公司與技術人員都在分享微服務架構的相關知識與實踐經驗,但我們發現,目前網上的這些相關文章中,要麽上來就是很有借鑒意義的幹貨,要麽就是
從 0 開始的微服務架構:(五)代碼給你,看如何用Docker支撐微服務
這一 復用 微軟 .com 擴展 版本發布 生產 通信 ibm 很好的一篇文章,全面、系統。 雖然已經紅了很久,但是“微服務架構”正變得越來越重要,也將繼續火下去。各個公司與技術人員都在分享微服務架構的相關知識與實踐經驗,但我們發現,目前網上的這些相關文章中,要麽上來就
從 0 開始的微服務架構:(四)如何保障微服務架構下的數據一致性
網上 行數 解決方案 open 了解 傳播 發的 目的 cati 雖然已經紅了很久,但是“微服務架構”正變得越來越重要,也將繼續火下去。各個公司與技術人員都在分享微服務架構的相關知識與實踐經驗,但我們發現,目前網上的這些相關文章中,要麽上來就是很有借鑒意義的幹貨,要麽就是以
微服務架構:基於微服務和Docker容器技術的PaaS雲平臺架構設計(微服務架構實施原理)
基於微服務架構和Docker容器技術的PaaS雲平臺建設目標是給我們的開發人員提供一套服務快速開發、部署、運維管理、持續開發持續整合的流程。平臺提供基礎設施、中介軟體、資料服務、雲伺服器等資源,開發人員只需要開發業務程式碼並提交到平臺程式碼庫,做一些必要的配置,
華為8年架構專家總結:微服務架構中zuul的兩種隔離機制實驗
ZuulException REJECTED_SEMAPHORE_EXECUTION 是一個最近在效能測試中經常遇到的異常。查詢資料發現是因為zuul預設每個路由直接用訊號量做隔離,並且預設值是100,也就是當一個路由請求的訊號量高於100那麼就拒絕服務了,返回
docker環境下部署的微服務架構: zookeeper和kafka部署
轉載自:http://www.jianshu.com/p/263164fdcac7 kafka簡單介紹 Kafka 是 LinkedIn 開源的一種高吞吐量的分散式釋出訂閱訊息系統,kafka的誕生就是為了處理海量日誌資料,所以kafka處理訊息的效率非常高,即使是非常
微服務架構:動態配置中心搭建
pre 有著 ice zed start nbsp ack pom.xml文件 之間 版權聲明:本文為博主原創文章,轉載請註明出處,歡迎交流學習! 在微服務架構中,服務之間有著錯綜復雜的依賴關系,每個服務都有自己的依賴配置,在運行期間很多配置會根據訪問流量等因
Spring Cloud構建微服務架構:服務消費(基礎)
消費 ring str frame emp default class a template pom.xml 使用LoadBalancerClient在Spring Cloud Commons中提供了大量的與服務治理相關的抽象接口,包括DiscoveryClient、這裏我
Spring Cloud構建PC蛋蛋源碼下載微服務架構:服務消費(基礎)
true ota ctu temp control lan prope 源碼下載 builder PC蛋蛋源碼下載論壇:haozbbs.com Q1446595067 使用LoadBalancerClient 在Spring Cloud Commons中提供了大量的與服務治
Spring Cloud構建微服務架構:服務註冊與發現 Eureka
Spring Cloud構建微服務架構:服務註冊與發現Eureka 【Dalston版】 原創 2018-04-10 宗野 Spring Cloud 已經
微服務架構中zuul的兩種隔離機制實驗
ZuulException REJECTED_SEMAPHORE_EXECUTION 是一個最近在效能測試中經常遇到的異常。查詢資料發現是因為zuul預設每個路由直接用訊號量做隔離,並且預設值是100,也就是當一個路由請求的訊號量高於100那麼就拒絕服務了,返回500。 訊號量隔離 既然預設值太小,那麼就
深解微服務架構:從過去,到未來
微服務的誕生 微服務架構(MicroserviceArchitect)是一種架構模式,它提倡將單塊架構的應用劃分成一組小的服務,服務之間互相協調、互相配合,為使用者提供最終價值。每個服務執行在其獨立的程序中,服務與服務間採用輕量級的通訊機制互相溝通。每個
Spring Cloud構建微服務架構:服務容錯保護(Hystrix服務降級)
tro sco load 服務架構 延遲 正常 map ati href 動手試一試 在開始使用Spring Cloud Hystrix實現斷路器之前,我們先拿之前實現的一些內容作為基礎,其中包括: eureka-server工程:服務註冊中心,端口:1001 eurek
Spring Cloud構建微服務架構:服務消費(Ribbon)
Spring Cloud Ribbon Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端負載均衡的工具。它是一個基於HTTP和TCP的客戶端負載均衡器。它可以通過在客戶端中配置ribbonServerList來設定服務端列表去輪詢訪問以達到均衡負載的作用。 當Rib
Spring Cloud構建微服務架構:服務消費(Feign)
Spring Cloud Feign Spring Cloud Feign是一套基於Netflix Feign實現的宣告式服務呼叫客戶端。它使得編寫Web服務客戶端變得更加簡單。我們只需要通過建立介面並用註解來配置它既可完成對Web服務介面的繫結。它具備可插拔的註解支援,包括Feign註解、JAX-RS註解
微服務架構:如何用十步解耦你的系統?
導言: 耦合性,是對模組間關聯程度的度量。耦合的強弱取決於模組間介面的複雜性、呼叫模組的方式以及通過介面傳送資料的多少。模組間的耦合度是指模組之間的依賴關係,包括控制關係、呼叫關係、資料傳遞關係。模組間聯絡越多,其耦合性越強,同時表明其獨立性越差。軟體設計中通常用耦合度和內聚度作為衡量模組獨立程度
Spring Cloud構建微服務架構:服務註冊與發現(Eureka、Consul)
Spring Cloud簡介 Spring Cloud是一個基於Spring Boot實現的雲應用開發工具,它為基於JVM的雲應用開發中涉及的配置管理、服務發現、斷路器、智慧路由、微代理、控制匯流排、全域性鎖、決策競選、分散式會話和叢集狀態管理等操作提供了一種簡單的開發方式。 Spring Cloud包含