標籤:響應式編程 Spring WebFlux
本系列文章索引《響應式Spring的道法術器》
前情提要 Spring WebFlux快速上手 | Spring WebFlux效能測試
1.4.3 Netflix的非同步化案例
前兩節通過gatling和簡單的樣本,我們見識了Spring WebFlux的服務端和用戶端的效能實力,在此基礎上,也就不難理解下邊的案例了。
Netflix是美國流媒體巨頭、世界最大的收費視頻網站,奧巴馬也追、習大大也提的《紙牌屋》就是它的自製劇,幾個月前還買下了國產劇《白夜追兇》的播放權。不過估計使用Spring Cloud的朋友可能比喜歡追劇的朋友對Netflix這個詞更加眼熟,因為Netflix幾乎開源了公司內部全部的微服務架構技術棧,Spring Cloud能夠完美整合Netflix的開源架構。這套架構在Netflix公司大規模分布式微服務環境中經過數年的生產環境檢驗被證明是可靠的。
截止到2016年,Netflix已經擁有8300+萬訂閱使用者,每天播放時間達到了1億2千萬小時,是北美互連網峰值下載量的1/3。為了支撐龐大的使用者訪問,Netflix從2009便下決心向雲原生的微服務生態系統演化,在2016年完成了整體應用遷徙到雲端,擁有500+的微服務,在系統演化的7年內,Netflix的流量增長了1000多倍,可謂是開著火箭換髮動機。
下面介紹一下這個令人膜拜的微服務架構實踐者是如何利用非同步非阻塞的技術來提高其API Gateway效能的(參考Zuul 2 : The Netflix Journey to Asynchronous, Non-Blocking Systems)。
在微服務架構中,通常少不了服務API Gateway這樣一個組件。用過Spring Cloud的朋友對Zuul這個組件應該是熟悉的。zuul是netflix開源的一個API Gateway伺服器,雲平台上提供動態路由,監控,彈性,安全等邊緣服務,相當於是所有服務API的“前台”。
如果不瞭解,也沒關係,先介紹一個Zuul的基礎功能——路由:
,作為“前台”的Zuul能夠根據一定的規則將到來的請求分發到各個具體的服務,僅就這一個功能來說,Zuul通常會承載較大流量,而且與上邊第二個測試的例子類似——商務邏輯很少,它的響應時間長度的主要由被路由服務的響應時間長度決定。
2016年以前,Netflix的Zuul 1本質上一個web servlet應用,因此是多線程的、阻塞的,也就是說對每一個Http串連都會用一個單獨的線程來處理。在Zuul 1中,對於IO操作,會再用一個背景工作執行緒來執行,背景工作執行緒中的IO操作執行完成後會通知處理請求的線程,操作完成前,後者是阻塞的。
這種方式與前邊的測試專案restTemplate-as-caller的最後一次測試是類似的,只不過Zuul 1並非用的Reactor的Scheduler,而可能是採用ExecutorService或類似方式實現的線程池。
Netflix的服務託管於AWS,正常情況下這種工作方式在多核的AWS雲執行個體中運轉還OK,但是如果後端服務出現問題,就有可能造成連鎖反應。
回想一下restTemplate-as-caller最後一次測試的結果,服務B的延遲是100ms,當並發使用者量達到6000時,服務A的95%響應時間長度會達到236ms,如果還有一個服務C依賴於服務A呢,回應時間就更長了,再加上此時使用者可能會不耐煩地頻繁重新整理頁面,情況會更糟。這時候如果看一下CPU的load,可能並不高,因為幾乎所有的請求都在阻塞和排隊中。
這是一種惡性迴圈。而在一個分布式系統裡,許多依賴不可避免的會出現類似的窘境甚至調用失敗,因此Netflix又開發了Hystrix組件(也整合在Spring Cloud中)來應對這種問題,它提供了熔斷、隔離、Fallback、cache、監控等功能,能夠在一個或多個依賴出現逾時、異常等問題時保證系統依然可用。
但Hystrix並非根本解決之道,問題的根源在於同步阻塞的服務調用。於是Netflix開發了Zuul 2,它基於Netty,以非同步非阻塞的方式來處理請求,一個CPU核心專心處理一個線程,每一個請求的生命週期存在於Event Loop和Callback中。如所示:
從資源成本的角度來說,由於不用為每一個請求開闢獨立的線程,能夠避免CPU線程切換、大量線程棧記憶體造成的資源浪費,基本只剩下檔案描述符和回調Listener的成本,從而Http串連成本顯著降低。此外,由於工作在一個線程上,CPU除了不用來回奔波於成百上千的線程,還能更好地利用一二級CPU緩衝,從而進一步提高效能。
Zuul 2上線之後的表現並未另Netflix失望,它輕鬆搞定了8300萬使用者(每個使用者還有多個裝置或瀏覽器)的持久串連(persistent connection)。
不同於計算密集型的應用,WEB應用通常是高並發和I/O密集型的,尤其是在微服務架構的應用中,CPU執行時間相對於阻塞時間來說通常要短得多,越是如此,非同步非阻塞越能發揮出顯著的效能提升效果。從這個案例可以看到,以非同步非阻塞的方式代替阻塞和多線程方式是提高效能的有效途徑。
(8)Netflix對API Gateway的非同步化改造——響應式Spring的道法術器