前一篇解析了服務(wù)是怎么進行注冊的滥崩,接下來解析一下服務(wù)注冊之后服務(wù)之間是如何發(fā)現(xiàn)彼此的末荐。
相對服務(wù)注冊而言服務(wù)發(fā)現(xiàn)就簡單很多了唠粥。就是Nacos客戶端調(diào)用Open api或者SDK查詢服務(wù)列表,服務(wù)端接受到請求后根據(jù)將查詢到服務(wù)包裝成json格式返回梆暮。
既然如此那客戶端是啥時候發(fā)起服務(wù)列表查詢?如果客戶端查的時差內(nèi)胧卤,剛好有服務(wù)實例有dowan掉的唯绍,那客戶端的請求豈不是有請求到dowan的服務(wù)實例去?不是吧枝誊?帶著這個疑問我們接著分析况芒,揭開一層層疑惑。
根據(jù)之前eureka的經(jīng)驗叶撒,客戶端本身通常會維護一個本地服務(wù)地址列表绝骚,不會在每次請求時都去請求一次服務(wù)端的來拉取最新的服務(wù)地址。那么這個本地服務(wù)地址列表就有一個時效性問題祠够。
老規(guī)矩我們看下spring-cloud-starter-alibaba-nacos-discovery包下的spring.facories文件很容易找到與服務(wù)發(fā)現(xiàn)相關(guān)的配置類压汪。
NacosWatch引起了我的注意為Nacos提供subscribe(String serviceName,EventListener listener)來進行訂閱監(jiān)聽。深入一步其實是namingService的subscribe機制古瓤,而nacos的NacosNamingService實現(xiàn)了這個接口止剖,我們進入到NacosNamingService的subscribe方法一探究竟,最后發(fā)現(xiàn)調(diào)用的HostReactor的subscribe方法
注意到客戶端有一個HostReactor類落君,在com.alibaba.nacos.client.naming.core包下穿香。
跟蹤進去在scheduleUpdateIfAbsent中發(fā)現(xiàn)新增了一個任務(wù)。
HostReactor它里面有一個UpdateTask線程绎速,每1s發(fā)送一次pull拉取請求扔水,獲取服務(wù)最新的地址列表。
更新服務(wù)的核心邏輯在updateService方法中
在看看processServiceJson方法朝氓,本地維護一個Map<String,ServiceInfo>?serviceInfoMap存儲服務(wù)信息,同時調(diào)用DiskCache.write(serviceInfo, this.cacheDir)方法把服務(wù)信息寫入本地緩存文件中;
對于服務(wù)端采取的是基于心跳機制push的方式實現(xiàn)的主届,由于服務(wù)端和服務(wù)提供者建立心跳機制赵哲,一旦服務(wù)出現(xiàn)故障,服務(wù)端察覺出后君丁,會發(fā)送一個push消息給Nacos客戶端枫夺,也就是我們的消費者。這個push消息是使用DatagramSocket來實現(xiàn)的绘闷。
服務(wù)消費者收到服務(wù)端發(fā)來的push消息之后橡庞,使用HostReactor中提供的ServiceInfo processServiceJson(String json)方法解析消息,并更新本地服務(wù)地址列表印蔗。
這里不贅述了扒最,如果不太清晰的話,可以參照下面的圖更容易理解服務(wù)動態(tài)感知原理