我們先從 Nginx 說起,了解為什么需要微服務。最初的服務化解決方案是給相同服務提供一個統一的域名,然后服務調用者向這個域發送 HTTP 請求,由 Nginx 負責請求的分發和跳轉。
這種架構存在很多問題:Nginx 作為中間層,在配置文件中耦合了服務調用的邏輯,這削弱了微服務的完整性,也使得 Nginx 在一定程度上變成了一個重量級的 ESB。圖 1 標識出了 Nginx 的轉發信息流走向。
服務的信息分散在各個系統,無法統一管理和維護。每一次的服務調用都是一次嘗試,服務消費方並不知道有哪些實例在給他們提供服務。這帶來了一些問題:
- 無法直觀地看到服務提供方和服務消費方當前的運行狀況與通信頻率;
- 消費方的失敗重發、負載均衡等都沒有統一策略,這加大了開發每個服務的難度,不利於快速演化。
為了解決上面的問題,我們需要一個現成的中心組件對服務進行整合,將每個服務的信息匯總,包括服務的組件名稱、地址、數量等。
服務的調用方在請求某項服務時首先通過中心組件獲取提供服務的實例信息(IP、端口等),再通過默認或自定義的策略選擇該服務的某一提供方直接進行訪問,所以考慮引入 Dubbo。
Dubbo 是阿里開源的一個 SOA 服務治理解決方案,文檔豐富,在國內的使用度非常高。圖 2 為 Dubbo 的基本架構圖,使用 Dubbo 構建的微服務已經可以較好地解決上面提到的問題。
從圖 2 中,可以看出以下幾點:
- 調用中間層變成了可選組件,消費方可以直接訪問服務提供方;
- 服務信息被集中到 Registry 中,形成了服務治理的中心組件;
- 通過 Monitor 監控系統,可以直觀地展示服務調用的統計信息;
- 服務消費者可以進行負載均衡、服務降級的選擇。
但是對於微服務架構而言,Dubbo 並不是十全十美的,也有一些缺陷,比如:
- Registry 嚴重依賴第三方組件(ZooKeeper 或者 Redis),當這些組件出現問題時,服務調用很快就會中斷。
- Dubbo 只支持 RPC 調用。這使得服務提供方與調用方在代碼上產生了強依賴,服務提供方需要不斷將包含公共代碼的 Jar 包打包出來供消費方使用。一旦打包出現問題,就會導致服務調用出錯。
Dubbo 的定位始終是一款 RPC 框架,而 Spring Cloud 的目標是微服務架構下的一站式解決方案。如果非要比較的話,Dubbo 可以類比到 Netflix OSS 技術棧,而 Spring Cloud 集成了 Netflix OSS 作為分布式服務治理解決方案,但除此之外 Spring Cloud 還提供了配置、消息、安全、調用鏈跟蹤等分布式問題解決方案。
當前由於 RPC 協議、注冊中心元數據不匹配等問題,在面臨微服務基礎框架選型時 Dubbo 與 Spring Cloud 只能二選一,這也是大家總是拿 Dubbo 和 Spring Cloud 做對比的原因之一。
Dubbo 已經適配到 Spring Cloud 生態,比如作為 Spring Cloud 的二進制通信方案來發揮 Dubbo 的性能優勢,Dubbo 通過模塊化以及對 HTTP 的支持適配到 Spring Cloud。
功能名稱 | Dubbo | Spring Cloud |
---|---|---|
服務注冊中心 | ZooKeeper | Spring Cloud Netflix Eureka |
服務調用方式 | RPC | REST API |
服務網關 | 無 | Spring Cloud Netflix Zuul |
斷路器 | 不完善 | Spring Cloud Netflix Hystrix |
分布式配置 | 無 | Spring Cloud Config |
服務跟蹤 | 無 | Spring Cloud Sleuth |
消息總線 | 無 | Spring Cloud Bus |
數據流 | 無 | Spring Cloud Stream |
批量任務 | 無 | Spring Cloud Task |
Spring Cloud 拋棄了 Dubbo 的 RPC 通信,采用的是基於 HTTP 的 REST 方式。嚴格來說,這兩種方式各有優劣。雖然從一定程度上來說,后者犧牲了服務調用的性能,但也避免了上面提到的原生 RPC 帶來的問題。而且 REST 相比 RPC 更為靈活,服務提供方和調用方,不存在代碼級別的強依賴,這在強調快速演化的微服務環境下顯得更加合適。