深入Java微服務之網關係列1:什麼是網關
- 2022 年 2 月 13 日
- 筆記
前言
近來,在想著重構一個新的產品。準備採用微服務的技術解決方案,來搭建基礎設施框架。網關,是一個必不可少的組件。那麼,網關到底是什麼?
其又有什麼特點或者特性,成為微服務必不可少的組件呢?今天,我們就來探討下這個問題。希望通過本文,大家能夠明白,為何用。
演變過程
傳統的單體技術架構,所有的內容,被打包進一個包內。為了保證,系統的穩定、安全,需要開發一些過濾器、攔截器,來實現對客戶端請求的過濾與攔截,以及完成最終請求的轉發。如下圖所示
微服務技術解決方案下,同樣需要為每個服務開發過濾器、攔截器來進行請求管理。但由於服務數量眾多,同時,客戶端形式多樣化,如果在每個服務身上開發,將會造成很大的程式碼冗餘與開發負擔。因此,期待,將相同的一些功能,抽取到一個服務內實現,這便成為了一個組件,就是現在的網關。
網關存在的原因:
-
解決微服務技術架構下,請求管理功能
-
解決微服務技術架構下,多客戶端的適配,採用單一入口,完成協議適配
網關的基本功能
微服務技術解決方案下的,網關,至少需要具備圖示基本功能。
-
網關作為單點入口,完成統一的請求管理
-
免去客戶端直接對接眾多微服務的複雜性,採用單點入口,實現路由轉發,從而實現服務調用
-
服務對於整個系統來講,是不穩定的,那麼網關,需要進行限流熔斷,保持系統的穩定與分區容錯性
-
對於服務調用的鏈路,網關有職責進行記錄,日誌監控,保證整個系統,在監控下工作
-
系統可能不僅僅是由自有客戶端調用,很多時候,系統開放能力API給外部,因此網關需要安全認證,來保證安全
這些年來,API網關正在經歷一些身份危機。
-
它們是否是集中的、共享的資源,從而促進了API對外部實體的暴露與治理?
-
它們是集群入口(ingress)哨兵,從而可以嚴格控制哪些用戶流量進入或離開集群嗎?
-
或者它們根據自己擁有的客戶端類型,使用某種API結合膠水來更簡潔地表達API?
-
當然,房間里的大象和我經常聽到的一個問題:「服務網格會使API網關過時嗎?
房間里的大象:英語習語,指的是一些雖然顯而易見,但卻由於可能造成尷尬、爭執、觸及敏感或禁忌等原因被人刻意忽視的事情。
一些背景
隨著技術發展日新月異,整個行業通過技術和架構模式進行快速洗牌,如果你說「所有這些都使我頭大」,也可以理解。在本文中,我希望總結出「 API網關」的不同身份,闡明公司中的哪些群體可以使用API網關(他們正在嘗試解決的問題),並重新關注這些首要原則。理想情況下,在本文結束時,您將更好地了解API基礎架構在不同層級、對不同團隊的作用,同時明白如何從每個層級獲得最大價值。
在深入探討之前,讓我們先明確API一詞的含義。
我對API的定義:
一個明確定義和目的型介面,通過網路調用,使軟體開發人員能夠以受控且方便的方式,對組織內的數據和功能進行編程訪問。
這些介面抽象了實現它們的技術架構細節。對於這些設計的網路端點,我們希望獲得一定程度的文檔、使用指南、穩定性和向後兼容性。
相反,僅僅因為我們可以通過網路與另一軟體進行通訊,並不一定意味著遠程端點就是符合此定義的API。許多系統相互通訊,但是通訊發生更加隨意,並在與耦合和其他因素之間進行權衡。
我們創建API來為業務的各個部分提供周全的抽象,以實現新的業務功能以及偶然的創新。
在談論API網關時,首先要提到的是API管理。
API管理
許多人從API管理的角度考慮API網關。這是公平的。但是,讓我們快速看一下此類網關的功能。
通過API Management,我們試圖解決「何時公開現有的API供他人使用」的問題,如何跟蹤誰使用這些API,實施關於允許誰使用它們的政策,建立安全流程來進行身份驗證和授權許可,同時創建一個服務目錄(該目錄可在設計時使用以促進API使用,並為有效治理奠定基礎)。
我們想解決「我們擁有要與他人共享,但要按我們的條款共享這些現有的、經過精心設計的API 」的問題。
API管理也做得很好,它允許用戶(潛在的API使用者)進行自助服務,簽署不同的API使用計劃(請考慮:在給定時間範圍內,在指定價格點上,每個端點每個用戶的調用次數)。有能力完成這些管理功能的基礎架構就是網關(API流量所經過的)。在網關層,我們可以執行身份驗證,速率限制,指標收集,其它策略執行等操作。
API Management Gateway
基於API網關的API管理軟體示例:
-
Google Cloud Apigee
-
Red Hat 3Scale
-
Mulesoft
-
Kong
在這個級別上,我們考慮的是API(如上定義)是如何最好地管理和允許對其進行訪問。我們不是在考慮伺服器,主機、埠、容器甚至服務(另一個定義不明確的詞)。
API管理(以及它們相應的網關)通常被作為由「平台團隊」、「集成團隊」或其它API基礎架構團隊所擁有的、嚴格控制的共享基礎架構。
需要注意的一件事:我們要小心,別讓任何業務邏輯進入這一層。如前一段所述,API管理是共享的基礎結構,但是由於我們的API流量經過了它,因此它傾向於重新創建「大包大攬的全能型」(認為是企業服務匯流排)網關,這會導致我們必須與之協調來更改我們的服務。從理論上講,這聽起來不錯。實際上,這最終可能成為組織的瓶頸。有關更多資訊,請參見這篇文章:具有ESB,API管理和Now…Service Mesh的應用程式網路功能?
集群入口
為了構建和實現API,我們將重點放在程式碼、數據、生產力框架等方面。但是,要想使這些事情中的任何一個產生價值,就必須對其進行測試,部署到生產中並進行監控。當我們開始部署到雲原生平台時,我們開始考慮部署、容器、服務、主機、埠等,並構建可在此環境中運行的應用程式。我們可能正在設計工作流(CI)和管道(CD),以利用雲平台快速遷移、更改、將其展示在客戶面前等等。
在這種環境中,我們可能會構建和維護多個集群來承載我們的應用程式,並且需要某種方式來訪問這些群集中的應用程式和服務。以Kubernetes為例思考。我們可能會通過Kubernetes Ingress來訪問Kubernetes集群(集群中的其它所有內容都無法從外部訪問)。這樣,我們就可以通過定義明確的入口點(例如域/虛擬主機、埠、協議等),嚴格控制哪些流量可以進入(甚至離開)我們的集群。
在這個級別上,我們可能希望某種「ingress網關」成為允許請求和消息進入群集的流量哨兵。在這個級別上,您的思考更多是「我的集群中有此服務,我需要集群外的人能夠調用它」。這可能是服務(公開API)、現有的整體組件、gRPC服務,快取、消息隊列、資料庫等。有些人選擇將其稱為API網關,而且實際上可能會做比流量的入口/出口更多的事情,但重點是這個層級的問題是屬於集群操作級別的。
Cluster Ingress Gateway
這些類型的ingress實現的示例包括:Envoy Proxy 及其基礎上的項目包括:
-
Datawire Ambassador
-
Solo.io Gloo
-
Heptio Contour
基於其他反向代理/負載均衡器構建的其它組件:
-
HAProxy
-
OpenShift』s Router (based on HAProxy)
-
NGINX
-
Traefik
-
Kong
此層級的集群入口控制器由平台團隊操作,但是,這部分基礎架構通常與更加去中心化的、自助服務工作流相關聯(正如您對雲原生平台所期望的那樣)。參見The 「GitOps」 workflow as described by the good folks at Weaveworks
API網關模式
關於「 API網關」一詞的另一種擴展是我在聽到該術語時通常想到的,它是與API網關模式最相似的。Chris Richardson在其「微服務模式」一書第8章很好地介紹了這種用法。我強烈建議您將此書用於此模式和其他微服務模式學習資料。可在他的microservices.io網站API Gatway Pattern可以進行快速瀏覽。簡而言之,API網關模式是針對不同類別的消費者來優化API的使用。這個優化涉及一個API間接訪問。您可能會聽到另一個代表API網關模式的術語是「前端的後端」,其中「前端」可以是字元終端(UI)、移動客戶端、IoT客戶端甚至其它服務/應用程式開發人員。
在API網關模式中,我們明顯簡化了一組API的調用,以模擬針對特定用戶、客戶端或使用者的「應用程式」內聚API。回想一下,當我們使用微服務構建系統時,「應用程式」的概念就消失了。API網關模式有助於恢復此概念。這裡的關鍵是API網關,一旦實現,它將成為客戶端和應用程式的API,並負責與任何後端API和其他應用程式網路端點(不滿足上述API定義的端點)進行通訊。
與上一節中的Ingress控制器不同,此API網關更接近開發人員的視角,而較少關注哪些埠或服務暴露以供集群外使用的方面。此「 API網關」也不同於我們管理現有API的API管理視角。此API網關將對後端的調用聚合在一起,這可能會公開API,但也可能是與API描述較少的東西,例如對舊系統的RPC調用,使用不符合「 REST」的協議的調用(如通過HTTP但不使用JSON),gRPC,SOAP,GraphQL、websockets和消息隊列。這種類型的網關也可用來進行消息級轉換、複雜的路由、網路彈性/回退以及響應的聚合。
如果您熟悉REST API的Richardson Maturity模型,就會發現相比Level 1–3,實現了API網關模式的API網關來集成了更多的Level 0請求(及其之間的所有內容)。
//martinfowler.com/articles/richardsonMaturityModel.html
這些類型的網關實現仍需要解決速率限制、身份驗證/授權、斷路、度量收集、流量路由等問題。這些類型的網關可以在集群邊緣用作集群入口控制器,也可以在集群內部用作應用程式網關。
API Gateway Pattern
此類API網關的示例包括:
-
Spring Cloud Gateway
-
Solo.io Gloo
-
Netflix Zuul
-
IBM-Strongloop Loopback/Microgateway
也可以使用更通用的編程或集成語言/框架(例如:
-
Apache Camel
-
Spring Integration
-
Ballerina.io
-
Eclipse Vert.x
-
NodeJS
由於這種類型的API網關與應用和服務的開發緊密相關,因此我們希望開發人員能夠參與幫助指定API網關公開的API,了解所涉及的任何聚合邏輯以及快速測試和更改此API基礎架構的能力。我們還希望運維人員或SRE對API網關的安全性、彈性和可觀察性配置有一些意見。這種層級的基礎架構還必須適應不斷發展的、按需的、自助服務開發人員工作流。可以通過查看GitOps模型獲取更多這方面資訊。
進入服務網格(Service Mesh)
在雲基礎架構上運行服務架構的一部分難點是,如何在網路中構建正確級別的可觀察性和控制。在解決此問題的先前迭代中,我們使用了應用程式庫和希望的開發人員治理來實現此目的。但是,在大規模和多種開發語言環境下,服務網格技術的出現提供了更好的解決方案。服務網格通過透明地實現為平台及其組成服務帶來以下功能:
-
服務到服務(即東西向流量)的彈性
-
安全性包括最終用戶身份驗證、相互TLS、服務到服務RBAC / ABAC
-
黑盒服務的可觀察性(專註於網路通訊),例如請求/秒、請求延遲、請求失敗、熔斷事件、分散式跟蹤等
-
服務到服務速率限制,配額執行等
精明的讀者會認識到,API網關和服務網格在功能上似乎有所重疊。服務網格的目的是通過在L7透明地解決所有服務/應用程式的這些問題。換句話說,服務網格希望融合到服務中(實際上它的程式碼並沒有嵌入到服務中)。另一方面,API網關位於服務網格以及應用程式之上(L8?)。服務網格為服務、主機、埠、協議等(東西向流量)之間的請求流帶來了價值。它們還可以提供基本的集群入口功能,以將某些此功能引入南北向。但是,這不應與API網關可以帶來北/南流量的功能相混淆。(一個在集群的南北向和一個是在一組應用程式的南北向)
Service Mesh和API網關在某些方面在功能上重疊,但是在它們在不同層面互補,分別負責解決不同的問題。理想的解決方案是將每個組件(API管理、API網關、服務網格)合適的安置到您的解決方案中,並根據需要在各組件間建立良好的邊界(或在不需要時排除它們)。同樣重要的是找到適合去中心化開發人員和運營工作流程的這些工具實現。即使這些不同組件的術語和標識存在混淆,我們也應該依靠基本原理,並了解這些組件在我們的體系結構中帶來的價值,從而來確定它們如何獨立存在和互補並存。
微服務不能沒有網關,就如同 Java 程式設計師不能沒有IDEA、Eclipse。為什麼呢?
之所以網關對微服務這麼重要,主要有以下幾點原因:
1. 解決 API 放哪裡的問題
要知道,採用微服務架構的系統本身是由很多的獨立服務單元組合起來的。而客戶端要調用系統,則必須通過系統提供的各種對外開放的 API 來實現。
問題來了,這些 API 要放在哪裡呢?直接放在組成系統的服務單元上行不行?
比如,在一套電商系統上,關於訂單相關的 API ,放在組成訂單服務的服務單元上;風控服務的 API ,放在組成風控服務的服務單元上。
好,咱們假設有這麼一個場景,有一位用戶想在這套電商系統上查看下商品詳情。那麼,這個查看商品詳情的操作,就可能:
-
調用商品服務的 API 獲取商品描述
-
調用評價服務的 API 獲取相關評價
-
調用商家服務的 API 獲取商家資訊
-
調用禮券服務的 API 獲取相關禮券
-
……
可以看到,就這麼一個商品查看操作,就可能會調用許多服務的 API。
那這些 API 如果全部分散到各個服務單元上,供客戶端調用,像查看商品這麼簡單的一次操作,客戶端就可能需要遠程訪問好幾次甚至十幾次伺服器。
微服務自己又講究把 API 的粒度劃分的很細,也就是說,可能從商品服務上調用商品資訊,不止是調用一次商品服務就夠了,很可能需要多次對商品服務的不同 API 進行調用,才能獲取到足夠的數據。
這樣一來,客戶端需要訪問伺服器的次數就更多了,可能十幾次都不夠,得幾十次。
這種多次訪問伺服器的行為,會極大延遲客戶端的介面響應時間,很不現實。
所以,把 API 放到各個業務相關的服務單元上,看上去問題很大。
那為什麼引入網關就能解決這個問題呢?
因為引入網關,就相當於在客戶端和微服務之間加了一層隔離。通常,網關本身會和各個服務單元處於同一個機房,這樣,客戶端做業務操作的時候,只需要訪問一次網關。然後剩下的事情,再由網關分別訪問同在一個機房的不同的服務,再把拿到的數據統一在網關封裝好,返回給客戶端就好。
2. 解決邊緣功能集成的問題
在一套微服務組成的系統里,除了必須的業務功能以外,還有為了系統自身的健壯與安全,以及微服務本身的管理,而必須引入的一些非業務功能。對於這些非業務又很重要的功能,我們統稱為邊緣功能。
還是拿電商系統為例,我們來看一些重要的邊緣功能。
假設因為我們做了一次非常大的促銷活動,導致流量過大,系統承載不了了。此時,為了保證系統本身的穩定,我們就需要把一些承載不了的流量給通過各種手段消化掉,一般的做法有三種:
-
限流:通過令牌桶等演算法,把一些額外的流量擋在系統外面,不讓其訪問。
-
降級:由於系統可能已經過載了,此時,我們就放棄處理一些服務和頁面的請求或者僅簡單處理,比如直接返回一個報錯。
-
熔斷:有些時候,系統過載過度或者上線出了 bug,降級都解決不了問題。比如,快取失效了,導致大量請求頻繁訪問了資料庫,而這種頻繁訪問資料庫可能造成了大量的 IO 操作,結果又去影響了資料庫所在的作業系統,同時,這個作業系統上又有著別的重要服務,直接也被影響了。對於這種連鎖反應,我們稱之為雪崩。而為了防止雪崩,我們就會堅決把快取失效導致資料庫被頻繁訪問的服務給停掉,這就是熔斷。
可以看到,像限流、降級、熔斷這些系統保障策略,最合適的地方應該是有一個集中的請求入口點,就像古時候,老百姓進城需要過城門那樣。
當系統出現問題的時候,直接就在這個入口點做相應的操作即可。
-
限流,就直接在這個入口點限制後續請求。
-
降級,就直接在這個入口點判斷請求想要訪問的服務或者頁面,直接報錯返回。
-
熔斷,就直接在這個入口點,斷開所有訪問特定服務的請求連接,然後再把後繼對特定服務的訪問,也統統攔在門外。
在電商系統里,有很多特殊場景的介面,需要受到嚴格的限制。
比如,支付介面,訪問它就需要認證和許可權控制。又比如,對於系統的訪問,有時候不能讓國外的去訪問中國的網站,這就需要限制客戶端的訪問 IP,所以系統還需要認證和授權功能。
那這種認證和授權也最合適放在請求的一個集中入口點,統一實現。
還記得上面咱們說過的網關的 API 統一存放嗎?我們只需要對這些 API 做對應的許可權設置,當請求訪問特殊場景介面的時候,必定會通過 API 訪問。所以,限制介面的訪問,本質上就是對特定 API 的限制,那麼,放在網關再合適不過了。
現實里,我們有時候需要把線上的流量鏡像出來,轉發到灰度環境,利用這些鏡像出來的流量既可以用於小範圍測試,又可以更好的評估系統所能承載的最大吞吐量,也因此,系統需要有一個統一入口做分流。
可以看到,無論是系統需要的保障策略,認證授權,還是流量分流等功能,都應該放到一個統一的請求入口處才能得到最好的實現。網關恰好就承擔了這麼個統一請求入口的角色。
所以,對於微服務中,林林總總的邊緣功能,往往會通過插件的形式,集成在 API 網關中。
3. 解耦了客戶端和後端微服務
一套項目,在使用微服務模式的初期,往往後端變化是十分頻繁的。
頻繁變化的原因有很多,像業務領域劃分不合適啊,像某個業務模組急速膨脹啊,都可能導致後端微服務的劇烈變化。
在這種情況下,如果沒有網關,很可能就會出現客戶端需要被迫隨著後端的變化而變化的情況。
比如,在電商系統里,初期我們很可能會把風控服務做的非常小。隨著業務的發展,風控服務越來越龐大,此時,風控服務就可能被分解為決策引擎和分析中心等更多更細的服務。
在電商里,風控往往是下單、支付等操作的必要前置操作。如果沒有網關去分隔開客戶端和微服務,客戶端直接和風控服務打交道,那麼風控服務拆分,API 必然不會穩定,API 的變化,自然會引發調用 API 客戶端程式碼的變化。
有了網關之後,情況就好了很多了。當風控服務本身頻繁變化的時候,我們只需要改動網關的程式碼就好。而伺服器程式碼的升級可是遠遠要比客戶端程式碼的升級容易太多了。
參考鏈接://juejin.cn/post/6918211351257022471
jianshu.com/p/9fab0982c6bb
微信公眾號【程式設計師黃小斜】作者是前螞蟻金服Java工程師,專註分享Java技術乾貨和求職成長心得,不限於BAT面試,演算法、電腦基礎、資料庫、分散式、spring全家桶、微服務、高並發、JVM、Docker容器,ELK、大數據等。關注後回復【book】領取精選20本Java面試必備精品電子書。