之前在做顧問和咨詢項目的時候,見到了一種非常經典的關於API網關和注冊中心的錯誤用法。這個案例在我的星球里已經分享過,沒想到最近又碰到了兩個類似的使用姿勢。也許這樣的問題還存在不少團隊的應用中,所以拿出來再分享一下,希望可以幫助讀者更好的理解注冊中心與API網關的作用,並將它們用對地方!
在微服務架構中,我們都會使用API網關來作為暴露服務的唯一出口。這樣可以將與業務無關的各項控制,集中的在API網關中進行統一管理,從而使得業務服務可以更加專注於業務領域本身。
而在微服務構建的系統內部,各個服務之間的調度,我們通常采用注冊中心和客戶端負載均衡的方式來實現服務之間的調用。
所以,大致的結構是這樣子的:

在這樣的架構實踐中,注冊中心和API網關的功能,主要有以下兩點:
- API網關通過注冊中心發現所有后端服務,從來實現動態代理
- 后端服務集群間,通過注冊中心互相發現對方,而實現直接調用(通常使用Ribbon、Feign這些框架)
下面就來具體說說今天的主角(錯誤案例),先上圖:

注意圖中的兩個地方:
- 存在兩套網關,一套對內訪問、一套對外訪問
- 對內訪問的網關實際就是起到了一個代理作用,較之前的圖對比以下,就知道,這個方案中並沒有利用到服務治理機制去直接讓服務A調用服務B,而是通過網關去做了一次代理。
更震驚的是,在我看到代碼的時候,他們居然也是用feign來編寫服務間調用的,但在配置請求路徑的時候,是使用在內部API網關上配置的二級域名來實現(比如:http://service-name.didispace.com/api-path,這里service-name對應不同的服務名),而熟悉Spring Cloud的讀者都知道,其實service-name.didispace.com這部分直接用服務名替代就可以了...是不是瞬間有種脫褲子放x的感覺?
如果這樣來使用的話,其實引入注冊中心的用處就很小了,實際上只有給兩個網關提供了集中的后端服務發現功能。如果要實現這種功能,其實注冊中心都可以不需要,每個服務都直接上報地址給網關就好了,架構會更加簡單。
同時,在這樣的實現方式之下,內部調用都要經過內部網關多一跳的調度過程,除了要多出內部網關的部署資源之外,每一次內部調用的時間開銷實際上都大了。所以這樣的用法是非常不推薦的!
對於API網關的定位,還是以作為對外出口的管理為最佳,內部的代理調用,均交給服務注冊與發現機制 + 客戶端負載均衡就ok了。沒有必要再增加一層代理,不但增加部署成本,同時還會降低的性能。完全是賠了夫人又折兵的做法,非常不可取!
除非有一種情況,如果你的業務集群很大,對前端暴露用一套網關,同時后端服務有幾千幾萬,由很多個不同的團隊在維護,那么在團隊的邊界處設立內部的網關,那還是合理的。同時這種情況下,對於注冊中心,按團隊做隔離也是有必要的。因為這樣可以分而治之,更好的做好接口的訪問控制與管理。但是,如果你本身服務不多,團隊也不大,那就別折騰這么復雜的架構了,越復雜穩定性就越難保障,這點一定要平衡好。
最后,大家結合自己團隊的注冊中心與API網關應用是否有犯一樣的問題呢?或者如果有其他問題與疑問,不妨留言交流一下?也可以加入我們的技術交流群一起探討技術問題!
