大家好,我是寶哥!
Provider APP
:服務(wù)提供者
Consumer APP
:服務(wù)消費者
Name Server
:通過VIP(Virtual IP)或DNS的方式實現(xiàn)Nacos高可用集群的服務(wù)路由
Nacos Server
:Nacos服務(wù)提供者,里面包含的Open API是功能訪問入口,Conig Service、Naming Service 是Nacos提供的配置服務(wù)、命名服務(wù)模塊。Consitency Protocol是一致性協(xié)議,用來實現(xiàn)Nacos集群節(jié)點的數(shù)據(jù)同步,這里使用的是Raft算法(Etcd、Redis哨兵選舉)
Nacos Console
:控制臺
服務(wù)實例在啟動時注冊到服務(wù)注冊表,并在關(guān)閉時注銷
服務(wù)消費者查詢服務(wù)注冊表,獲得可用實例
服務(wù)注冊中心需要調(diào)用服務(wù)實例的健康檢查API來驗證它是否能夠處理請求
在Spring-Cloud-Common包中有一個類org.springframework.cloud. client.serviceregistry .ServiceRegistry
,它是Spring Cloud提供的服務(wù)注冊的標準。集成到Spring Cloud中實現(xiàn)服務(wù)注冊的組件,都會實現(xiàn)該接口。
該接口有一個實現(xiàn)類是NacoServiceRegistry。
SpringCloud集成Nacos的實現(xiàn)過程:
在spring-clou-commons
包的META-INF/spring.factories
中包含自動裝配的配置信息如下:
其中AutoServiceRegistrationAutoConfiguration
就是服務(wù)注冊相關(guān)的配置類:
在AutoServiceRegistrationAutoConfiguration
配置類中,可以看到注入了一個AutoServiceRegistration
實例,該類的關(guān)系圖如下所示。
可以看出, AbstractAutoServiceRegistration
抽象類實現(xiàn)了該接口,并且最重要的是NacosAutoServiceRegistration
繼承了AbstractAutoServiceRegistration
。
看到EventListener我們就應(yīng)該知道,Nacos是通過Spring的事件機制繼承到SpringCloud中去的。
AbstractAutoServiceRegistration
實現(xiàn)了onApplicationEvent抽象方法,并且監(jiān)聽WebServerInitializedEvent
事件(當Webserver初始化完成之后) , 調(diào)用this.bind ( event )
方法。
最終會調(diào)用NacosServiceREgistry.register()
方法進行服務(wù)注冊。
在NacosServiceRegistry.registry
方法中,調(diào)用了Nacos Client SDK中的namingService.registerInstance
完成服務(wù)的注冊。
跟蹤NacosNamingService的registerInstance()
方法:
通過beatReactor.addBeatInfo()
創(chuàng)建心跳信息實現(xiàn)健康檢測, Nacos Server必須要確保注冊的服務(wù)實例是健康的,而心跳檢測就是服務(wù)健康檢測的手段。
serverProxy.registerService()
實現(xiàn)服務(wù)注冊
心跳機制:
從上述代碼看,所謂心跳機制就是客戶端通過schedule定時向服務(wù)端發(fā)送一個數(shù)據(jù)包 ,然后啟動-個線程不斷檢測服務(wù)端的回應(yīng),如果在設(shè)定時間內(nèi)沒有收到服務(wù)端的回應(yīng),則認為服務(wù)器出現(xiàn)了故障。Nacos服務(wù)端會根據(jù)客戶端的心跳包不斷更新服務(wù)的狀態(tài)。
注冊原理:
Nacos提供了SDK和Open API兩種形式來實現(xiàn)服務(wù)注冊。
Open API:
SDK:
這兩種形式本質(zhì)都一樣,底層都是基于HTTP協(xié)議完成請求的。所以注冊服務(wù)就是發(fā)送一個HTTP請求:
對于nacos服務(wù)端,對外提供的服務(wù)接口請求地址為nacos/v1/ns/instance
,實現(xiàn)代碼咋nacos-naming
模塊下的InstanceController類中:
從請求參數(shù)匯總獲得serviceName(服務(wù)名)和namespaceId(命名空間Id)
調(diào)用registerInstance注冊實例
創(chuàng)建一個控服務(wù)(在Nacos控制臺“服務(wù)列表”中展示的服務(wù)信息),實際上是初始化一個serviceMap,它是一個ConcurrentHashMap集合
getService,從serviceMap中根據(jù)namespaceId和serviceName得到一個服務(wù)對象
調(diào)用addInstance添加服務(wù)實例
根據(jù)namespaceId、serviceName從緩存中獲取Service實例
如果Service實例為空,則創(chuàng)建并保存到緩存中
通過putService()
方法將服務(wù)緩存到內(nèi)存
service.init()
建立心跳機制
consistencyService.listen
實現(xiàn)數(shù)據(jù)一致性監(jiān)聽
service.init ( )
方法的如下圖所示,它主要通過定時任務(wù)不斷檢測當前服務(wù)下所有實例最后發(fā)送心跳包的時間。如果超時,則設(shè)置healthy為false表示服務(wù)不健康,并且發(fā)送服務(wù)變更事件。
在這里請大家思考一一個問題,服務(wù)實例的最后心跳包更新時間是誰來觸發(fā)的?實際上前面有講到, Nacos客戶端注冊服務(wù)的同時也建立了心跳機制。
putService方法,它的功能是將Service保存到serviceMap中:
繼續(xù)調(diào)用addInstance方法把當前注冊的服務(wù)實例保存到Service中:
總結(jié):
Open API:
SDK:
InstanceController中的list方法:
解析請求參數(shù)
通過doSrvIPXT返回服務(wù)列表數(shù)據(jù)
根據(jù)namespaceId、serviceName獲得Service實例
從Service實例中基于srvIPs得到所有服務(wù)提供者實例
遍歷組裝JSON字符串并返回
可以通過subscribe方法來實現(xiàn)監(jiān)聽,其中serviceName表示服務(wù)名、EventListener表示監(jiān)聽到的事件:
具體調(diào)用方式如下:
或者調(diào)用selectInstance方法,如果將subscribe屬性設(shè)置為true,會自動注冊監(jiān)聽:
Nacos客戶端中有一個HostReactor類,它的功能是實現(xiàn)服務(wù)的動態(tài)更新,基本原理是:
客戶端發(fā)起時間訂閱后,在HostReactor中有一個UpdateTask線程,每10s發(fā)送一次Pull請求,獲得服務(wù)端最新的地址列表
對于服務(wù)端,它和服務(wù)提供者的實例之間維持了心跳檢測,一旦服務(wù)提供者出現(xiàn)異常,則會發(fā)送一個Push消息給Nacos客戶端,也就是服務(wù)端消費者
服務(wù)消費者收到請求之后,使用HostReactor中提供的processServiceJSON解析消息,并更新本地服務(wù)地址列表
來源:blog.csdn.net/cold___play/article/
details/108032204