服務調用問題
單實例情況:可以採用點對點的 HTTP 直接調用,採用 IP + Port + 接口的形式進行。也可以對外暴露 WebService 服務供外部模塊調用,但 WebService 的形式 顯示比 HTTP的形式稍重一些,在實際的業務開發過程中,越來越的產品開發採用輕量級的 HTTP 協議進行數據交互。如果模塊增多,將會形成蜘蛛網的形式,非常不利於開發維護。
多實例的情況:為應對服務的壓力,採用多實例集羣部署已成為簡捷易用的解決方案。僅僅多實例部署後,直接面臨一個問題,調用方如何知曉調用哪個實例,當實例運行失敗後,如何轉移到別的實例上去處理請求?如果採用了負載均衡,但往往是靜態的,在服務不可用時,如果動態的更新負載均衡列表,保證調用者的正常調用呢?
面對以上兩種情況,服務註冊中心的需求迫在眉捷,將所有的服務統一的、動態的管理起來。
三種角色
在微服務架構下,主要有三種角色:服務提供者(RPC Server)、服務消費者(RPC Client)和服務註冊中心(Registry)。
- RPC Server提供服務,在啓動時,根據服務發佈文件server.xml中的配置的信息,向Registry註冊自身服務,並向Registry定期發送心跳彙報存活狀態。
- RPC Client調用服務,在啓動時,根據服務引用文件client.xml中配置的信息,向Registry訂閲服務,把Registry返回的服務節點列表緩存在本地內存中,並與RPC Sever建立連接。
- 當RPC Server節點發生變更時,Registry會同步變更,RPC Client感知後會刷新本地內存中緩存的服務節點列表。
- RPC Client從本地緩存的服務節點列表中,基於負載均衡算法選擇一台RPC Sever發起調用。
服務註冊
服務註冊中心作分佈式服務框架的核心模塊,要實現的功能是服務的註冊、訂閲,與之相應的功能是註銷、通知這四個功能。
註冊中心:在註冊中心服務端,有一個用來管理服務的容器,他保存着所有服務的實例。(包括服務調用者)(底層結構是雙層map、mysql數據庫等)
服務發現
一般來説服務發現的完整流程,應該是先從註冊中心獲取到服務的實例列表,然後再根據自身的需求(負載均衡策略),來選擇其中的部分實例或者按照一定的流量分配機制來訪問不同的服務提供者。
服務管理過程
所有的服務都與註冊中心發生連接,由註冊中心統一配置管理,不再由實例自身直接調用。服務管理過程大致過程如下:
- 服務提供者啓動時,將服務提供者的信息主動提交到服務註冊中心進行服務註冊。
- 服務調用者啓動時,將服務提供者信息從註冊中心下載到調用者本地,調用者從本地的服務提供者列表中,基於某種負載均衡策略選擇一台服務實例發起遠程調用,這是一個點到點調用的方式。
- 服務註冊中心能夠感知服務提供者某個實例下線,同時將該實例服務提供者信息從註冊中心清除,並通知服務調用者集羣中的每一個實例,告知服務調用者不再調用本實例,以免調用失敗。
健康檢查機制
當前主流的註冊中心,對於健康檢查機制主要都採用了 TTL(Time To Live)機制,即客户端在一定時間沒有向註冊中心發送心跳,那麼註冊中心會認為此服務不健康,進而觸發後續的剔除邏輯。
以ZooKeeper為例,它是基於ZooKeeper客户端和服務端的長連接和會話超時控制機制,來實現服務健康狀態檢測的。
在ZooKeeper中,客户端和服務端建立連接後,會話也隨之建立,並生成一個全局唯一的Session ID。服務端和客户端維持的是一個長連接,在SESSION_TIMEOUT週期內,服務端會檢測與客户端的鏈路是否正常,具體方式是通過客户端定時向服務端發送心跳消息(ping消息),服務器重置下次SESSION_TIMEOUT時間。如果超過SESSION_TIMEOUT後服務端都沒有收到客户端的心跳消息,則服務端認為這個Session就已經結束了,ZooKeeper就會認為這個服務節點已經不可用,將會從註冊中心中刪除其信息。
nacos:服務提供者會自動給註冊中心上報心跳;當服務提供者的某個服務一段時間沒有上報心跳時,註冊中心會主動尋問服務提供者,若該服務不健康,則從註冊中心刪除該服務,註冊中心給服務調用者更新服務列表
Nacos 提供了兩種服務類型供用户註冊實例時選擇,分為臨時實例和永久實例。(但是在 Nacos2.0 中我們將是否持久化的數據抽象至服務級別,且不再允許一個服務同時存在持久化實例和非持久化實例,實例的持久化屬性繼承自服務的持久化屬性。)
臨時實例只是臨時存在於註冊中心中,會在服務下線或不可用時被註冊中心剔除,臨時實例會與註冊中心保持心跳,註冊中心會在一段時間沒有收到來自客户端的心跳後會將實例設置為不健康,然後在一段時間後進行剔除。
永久實例在被刪除之前會永久的存在於註冊中心,且有可能並不知道註冊中心存在,不會主動向註冊中心上報心跳,那麼這個時候就需要註冊中心主動進行探活。一些基礎的組件例如數據庫、緩存等,這些往往不能上報心跳,這種類型的服務在註冊時,就需要作為持久化實例註冊。
白名單機制
在實際的微服務測試和部署時,通常包含多套環境,比如生產環境一套、測試環境一套。開發在進行業務自測、測試在進行迴歸測試時,一般都是用測試環境,部署的RPC Server節點註冊到測試的註冊中心集羣。但經常會出現開發或者測試在部署時,錯誤的把測試環境下的服務節點註冊到了線上註冊中心集羣,這樣的話線上流量就會調用到測試環境下的RPC Server節點,可能會造成意想不到的後果。
為了防止這種情況發生,註冊中心需要提供一個保護機制,你可以把註冊中心想象成一個帶有門禁的房間,只有擁有門禁卡的RPC Server才能進入。在實際應用中,註冊中心可以提供一個白名單機制,只有添加到註冊中心白名單內的RPC Server,才能夠調用註冊中心的註冊接口,這樣的話可以避免測試環境中的節點意外跑到線上環境中去。
總結
註冊中心可以説是實現服務化的關鍵,因為服務化之後,服務提供者和服務消費者不在同一個進程中運行,實現瞭解耦,這就需要一個紐帶去連接服務提供者和服務消費者,而註冊中心就正好承擔了這一角色。此外,服務提供者可以任意伸縮即增加節點或者減少節點,通過服務健康狀態檢測,註冊中心可以保持最新的服務節點信息,並將變化通知給訂閲服務的服務消費者。
註冊中心一般採用分佈式集羣部署,來保證高可用性,並且為了實現異地多活,有的註冊中心還採用多IDC部署,這就對數據一致性產生了很高的要求,這些都是註冊中心在實現時必須要解決的問題。
參考:
https://nacos.io/docs/ebook/ynstox/
https://www.cnblogs.com/Xianhuii/p/17112392.html
SpringCloud微服務實戰
從0開始學微服務