服務發現的概念比較簡單,但是微服務架構中的服務發現並不簡單。

配置文件方案

我們假設存在一個前後端分離的項目,前端項目FE通過調用後端服務BE的介面來實現業務邏輯交互。在這個過程中,前端的項目可以在配置文件裡面寫入後端服務的地址來進行通信。在這種情況下,從宏觀層面,對於前端項目來說後端項目的發現是通過配置好的地址來完成的。

實際上通過在配置文件裡面寫入一個或者多個目標通信服務的地址是一開始我們進行服務發現的最簡單的方案。比如對於 Nginx 的反向代理來說,我們通過 upstream 指定用於定義每個後端的 server 指令就是如此。

這種配置文件的方案存在什麼問題呢?其中最簡單的問題就是維護不方便,無法適應動態變化。假設服務A需要調用服務B的介面,然後在服務A的配置文件裡面配置了三個服務B的實例地址。在正常的情況下,服務A可以通過輪詢或者其他帶權重的方式來訪問服務B的任何一個實例。但是假設這個時候服務B的實例有一個出現了故障,在這種情況下,我們必須從配置文件裡面把這個實例地址移除,然後重啟A服務,纔能夠讓A不再調用已故障的服務B的實例。

當然對於 Nginx 來講,我們可以配置讓 Nginx 忽略某些已故障的 upstream server。但是對於一般的業務服務A來講,把Nginx的這套邏輯重新實現一遍很明顯成本並不低。另外當這個大的業務體系裡面有太多像A這樣的服務時,實現故障偵測並自動忽略的成本就更高了。

除了服務故障之外,服務B的實例地址變更也是個大問題。在傳統的基於物理機或者虛擬機的情況下,服務B的實例地址升級或者重啟後可以保持不變。但是在今天 Kubernetes 等基於容器的分散式編排系統中,服務B的實例地址變更是很平常的事情。無論是實例升級還是實例故障重啟或者是實例被 Kubernetes自動調度都會導致服務B的實例地址發生變更。所以對於服務A來講,通過配置文件去維護服務B的地址簡直就是不可能的。

資料庫的方案

既然基於配置文件的方案不方便進行維護,那麼我們可以基於資料庫的方案來支持動態的服務地址修改。在很多的系統中,這種方式仍然存在著。我們可以通過編程語言調用SQL的方式來完整配置的更新。似乎看上去比基於配置文件的方式要快得多。

但是我們上面還提到一個關於維護服務實例之外的問題,即服務的狀態偵測。當有實例故障的時候我們要停止到該實例的調用,然後在該服務實例恢復正常之後,還要能夠恢復對該實例的調用。這裡面就不可避免地要週期性地輪詢這些服務的狀態,然後去更新資料庫。

這種週期性輪詢的時間間隔就和你能容忍的服務失敗時間和服務恢復時間有關係。如果你希望能夠儘快發現服務失敗或恢復正常的服務調用,那麼這個輪詢間隔就比較長。

所以在這種方案的情況下,你的服務自身仍然需要去實現這個服務偵測的邏輯。本質上和基於配置文件的方式沒有區別。

在微服務架構中,由於服務的創建和銷毀頻率遠比傳統的服務要高,這會導致各個服務實例的地址發生大量的變化,所以無論是基於配置文件還是基於資料庫,這種手動的維護工作量還是無法實現的。而且由於各個服務自身要實現對提供服務的目標實例進行健康偵測,無疑會給業務代碼帶來大量重複的而又業務無關的功能。

註冊中心方案

既然這種服務發現的功能和服務健康偵測的功能需要每個服務都要具備,那麼我們就可以把這組功能獨立出來,交給專門的服務去完成,也就是說服務的實例地址有個中心化的管理。這個服務就是註冊中心。

對於上面的兩個問題,註冊中心通過如下的方法來實現。

首先,每個服務啟動完畢之後就向註冊中心發送自己的服務名稱和實例地址。

然後,註冊中心負責偵測每個服務實例的健康狀態並決定是否將該實例地址返回給根據服務名稱查詢實例地址的請求方。

最後,每個服務調用方拿著這個目標服務地址去請求相關的介面,完成業務邏輯的交互。

在上面的方案中,由於註冊中心接管了服務的註冊和查詢,所以所有的業務服務就不再需要維護目標服務的實例地址,也不再需要去偵測它們的健康狀況了。所有的一切都交給了註冊中心去完成。

小結

以上就是微服務架構體系中的服務註冊和服務發現的原理。這個架構的產生主要是隨著大型業務系統的部署和運維的架構的變化而產生的。所有的方案都有適用的場景,所有的方案變化都是因為目標的場景發生了變化。技術和架構的演進,都是有跡可循。思考一個架構存在的合理性的關鍵就是思考它面對的場景。

另外如果我們稍微發散一下就會發現其實域名解析伺服器可以作為最典型的服務註冊中心。我們可以把域名當作服務的名稱,把域名解析到的具體地址作為實例地址。通過DNS的協議,我們可以利用域名來查詢到具體的IP地址;這個和我們通過服務名稱查詢到實例地址的過程是一樣的。通過域名我們屏蔽了具體的IP地址,為IP地址的維護提供了便利。基本上所有的HTTP客戶端庫在底層都能夠自動探測解析到的目標伺服器的IP連通性,然後決定連接哪個具體的IP;而當有任何一個IP故障時,我們都可以把它從解析裡面去除。通過服務端和客戶端兩邊都支持的方式來實現高可用。

而通過服務名稱去查詢實例地址,就讓我們屏蔽了具體的實例地址的維護過程。所以在微服務架構中,所有的服務之間都是直接通過服務名稱去調用的,具體的調用到哪個實例地址完全是有註冊中心和你的微服務客戶端決定的。

EOF


推薦閱讀:
相關文章