1. 程式人生 > >(8)Netflix對API網關的異步化改造——響應式Spring的道法術器

(8)Netflix對API網關的異步化改造——響應式Spring的道法術器

響應式編程 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網關性能的(參考Zuul 2 : The Netflix Journey to Asynchronous, Non-Blocking Systems)。

在微服務架構中,通常少不了服務API網關這樣一個組件。用過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網關的異步化改造——響應式Spring的道法術器