服務(wù)管理與通信的基礎(chǔ)原理分析
涉及輕微的源碼展示,可放心參考!
一、基礎(chǔ)簡介
服務(wù)注冊發(fā)現(xiàn)是微服務(wù)架構(gòu)中最基礎(chǔ)的能力,下面將從源碼層面分析實(shí)現(xiàn)邏輯和原理,在這之前要先來看下依賴工程的基礎(chǔ)結(jié)構(gòu),涉及如下幾個(gè)核心組件:
commons:服務(wù)組件的抽象聲明,本文只分析注冊發(fā)現(xiàn)與負(fù)載均衡;
nacos:當(dāng)下常用的注冊中心組件,用來進(jìn)行服務(wù)管理;
feign:服務(wù)間通信交互組件,在服務(wù)請求時(shí)涉及負(fù)載均衡的策略;
ribbon:在服務(wù)間通信請求時(shí),提供多種負(fù)載均衡的策略實(shí)現(xiàn);
在熟悉工程依賴之間的結(jié)構(gòu)時(shí),還要明白服務(wù)間交互的流程和原理,這樣在分析源碼設(shè)計(jì)時(shí),有一個(gè)清晰的思路與輪廓;如何實(shí)現(xiàn)下面的服務(wù)交互模式,在閱讀源碼工程時(shí),圍繞如下兩個(gè)核心邏輯:
- 注冊發(fā)現(xiàn):注冊時(shí)如何上報(bào)服務(wù)的信息數(shù)據(jù),這些數(shù)據(jù)以怎樣的方式管理;
- 負(fù)載均衡:當(dāng)請求的服務(wù)同時(shí)存在多個(gè)時(shí),以什么樣的策略選擇執(zhí)行請求的服務(wù);
在這里先簡單的聊一下個(gè)人在閱讀源碼工程時(shí)的基本思路,比如微服務(wù)組件:通常從配置參數(shù)作為切入口,觀察基于參數(shù)構(gòu)建的核心對象,再重點(diǎn)分析對象的管理模式,以及適配的擴(kuò)展能力,最后結(jié)合項(xiàng)目的應(yīng)用場景即可:
閱讀源碼最重要的是耐著心情慢慢看,并隨手畫下核心流程,實(shí)際上如果有一定的編程經(jīng)驗(yàn),不管是閱讀什么工程的源碼,只要用心去分析單點(diǎn)的實(shí)現(xiàn)原理,都算不上過度復(fù)雜,但是組件通常為了復(fù)用能力,會(huì)去適配多種復(fù)雜的場景,這樣勢必要采用抽象的封裝和設(shè)計(jì)模式,源碼工程的復(fù)雜度自然就會(huì)相應(yīng)提高,這個(gè)話題后續(xù)會(huì)細(xì)聊。
二、服務(wù)注冊
1、服務(wù)配置
首先從Nacos配置參數(shù)開始,這里只設(shè)置服務(wù)發(fā)現(xiàn)的兩個(gè)參數(shù):1Nacos注冊中心的服務(wù)端地址,2在服務(wù)的元數(shù)據(jù)中加載分支號(hào);然后來具體的看源碼流程:
在配置參數(shù)加載的過程中,有很多缺省的默認(rèn)值,所以需要關(guān)注最終會(huì)提供的參數(shù)信息,來判斷是否需要自定義設(shè)置,另外 AutoConfig 配置要重點(diǎn)看實(shí)例化的對象;斷點(diǎn)的流程可以按照如下的方式做設(shè)置,這里陳列的是在配置加載階段的幾個(gè)核心節(jié)點(diǎn):
- 參數(shù):NacosDiscoveryProperties#getNacosProperties
- 配置:NacosServiceAutoConfiguration#nacosServiceManager
- 構(gòu)建:NacosServiceManager#buildNamingService
NamingService是Nacos服務(wù)管理接口,涉及注冊、查詢、撤銷、檢查等多個(gè)方法,即對應(yīng)的是Nacos服務(wù)端的相應(yīng)API請求,在注冊執(zhí)行的階段會(huì)細(xì)說用法。
2、注冊構(gòu)建
看完服務(wù)配置之后再看注冊配置,對于配置中復(fù)雜的設(shè)計(jì),需要重點(diǎn)關(guān)注兩個(gè)信息:ConditionalOn和matchIfMissing,這樣很容易發(fā)現(xiàn)默認(rèn)加載:
- 配置:NacosServiceRegistryAutoConfiguration#nacosServiceRegistry
- 注冊:NacosServiceRegistry#register
- 實(shí)例:NacosServiceRegistry#getNacosInstanceFromRegistration
在構(gòu)建服務(wù)注冊的核心類NacosServiceRegistry時(shí),通過服務(wù)的登記信息轉(zhuǎn)換為注冊的實(shí)例化對象,然后通過NamingService接口方法,上報(bào)實(shí)例化對象;需要注意的是,雖然這里只看了Nacos中的相關(guān)API,但實(shí)際上API實(shí)現(xiàn)了諸多spring-cloud-commons包中聲明的接口,比如Registration、ServiceInstance等。
3、執(zhí)行上報(bào)
通常微服務(wù)的注冊中心組件,都是基于 server-client 架構(gòu)和部署方式,客戶端需要根據(jù)自身啟動(dòng)狀態(tài)去上報(bào)或者撤銷注冊,服務(wù)端負(fù)責(zé)統(tǒng)一維護(hù)注冊數(shù)據(jù):
- 實(shí)現(xiàn):NacosNamingService#registerInstance
- 執(zhí)行:NamingProxy#registerService
- 接口:InstanceController#register
在最終執(zhí)行服務(wù)注冊時(shí),其動(dòng)作本質(zhì)就是請求Nacos服務(wù)端的一個(gè)Post方法,并將配置數(shù)據(jù)上報(bào),例如:IP地址、端口、元數(shù)據(jù)、權(quán)重等;這樣客戶端注冊邏輯執(zhí)行完成,然后再看服務(wù)端數(shù)據(jù)可視化界面,就可以看到注冊的客戶端服務(wù)。
至于Nacos服務(wù)端是如何管理這些注冊數(shù)據(jù)的,參考部署版本的 nacos-naming 模塊源碼,閱讀上報(bào)接口和頁面中的列表加載的實(shí)現(xiàn)即可;注意在初始的配置文件中,加入的branch分支參數(shù)也在元數(shù)據(jù)結(jié)構(gòu)中。
在NamingService接口中,涉及多個(gè)服務(wù)管理的方法,在執(zhí)行原理上基本相同就不在贅述,這樣注冊中心的Client端和Server端就形成了通信機(jī)制,接下來再看Client端之間的通信。
三、服務(wù)通信
1、基礎(chǔ)配置
Feign在配置方面比較復(fù)雜,提供了多個(gè)場景下的適配能力,這里只以兩個(gè)常見的參數(shù)作為切入點(diǎn):1通信超時(shí)時(shí)間,2Http選型(采用默認(rèn)值);
- 參數(shù):FeignClientProperties#getConfig
- 注解:FeignClientsRegistrar#registerFeignClients
- 配置:FeignAutoConfiguration#feignContext
- 構(gòu)建:FeignClientFactoryBean#getTarget
這里要重點(diǎn)關(guān)注的是注解的掃描和注冊以及容器管理,要理解Feign的上下文環(huán)境需要明白上文中描述的服務(wù)間交互原理,然后參考FeignClientFactoryBean工廠類中構(gòu)建邏輯。
2、通信邏輯
雖然Feign注解的方式可以簡化開發(fā),但是在具體執(zhí)行的時(shí)候還是Http的請求響應(yīng)模式,這里可以參考LoadBalancerFeignClient類中的execute方法:
- 配置:FeignRibbonClientAutoConfiguration
- 通信構(gòu)建:LoadBalancerFeignClient#execute
- 負(fù)載均衡:AbstractLoadBalancerAwareClient#executeWithLoadBalancer
不管是Feign組件還是Spring框架,默認(rèn)的負(fù)載均衡策略都是采用Ribbon的實(shí)現(xiàn)方式,在上述流程中配置和負(fù)載均衡命令都依賴Ribbon組件,接下來看服務(wù)選擇策略。
四、負(fù)載均衡
1、命令構(gòu)建
這里構(gòu)建了調(diào)用負(fù)載均衡接口的命令,ILoadBalancer接口中提供服務(wù)管理的相關(guān)方法,其中最核心的就是chooseServer方法,然后結(jié)合具體的策略規(guī)則實(shí)現(xiàn)服務(wù)的選擇的功能:
- 命令構(gòu)建:LoadBalancerCommand.Builder#build
- 負(fù)載容器:LoadBalancerContext#getServerFromLoadBalancer
- 選擇接口:ILoadBalancer#chooseServer
2、策略規(guī)則
Ribbon組件中負(fù)載均衡的策略有好幾種規(guī)則,比如隨機(jī)選擇、Key匹配、權(quán)重傾斜等;在工作中常用的就是默認(rèn)規(guī)則即RoundRobinRule,以及基于Key設(shè)計(jì)的灰度模式,簡單做法就是服務(wù)啟動(dòng)時(shí)在元數(shù)據(jù)中添加的分支號(hào)作為匹配的標(biāo)識(shí);
- 規(guī)則設(shè)置:BaseLoadBalancer#setRule
- 隨機(jī)策略:RoundRobinRule#choose
- 過濾策略:PredicateBasedRule#choose
現(xiàn)在回到流程的開始看,通過Nacos組件進(jìn)行服務(wù)注冊和管理,通過Feign組件基于Ribbon負(fù)載均衡策略做服務(wù)通信,如果單看各節(jié)點(diǎn)組件的邏輯還比較容易理解,但是通過Spring框架做組件之間的協(xié)作調(diào)度時(shí),復(fù)雜程度明顯提高;
如果是剛開始閱讀源碼的階段,可以只關(guān)注相應(yīng)流程的核心邏輯,選擇性忽略細(xì)節(jié)的實(shí)現(xiàn)原理,當(dāng)然重點(diǎn)還是要多讀讀Spring的設(shè)計(jì),這樣時(shí)間久了自然會(huì)有很多收獲。
五、參考源碼
編程文檔:
https://gitee.com/cicadasmile/butte-java-note
應(yīng)用倉庫:
https://gitee.com/cicadasmile/butte-flyer-parent