亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

負載均衡器在分布式網(wǎng)絡(luò)中扮演著非常重要的角色。通過負載均衡,可以實現(xiàn)更好的性能和可靠性,同時提高系統(tǒng)的可擴展性和彈性。目前,SpringCloud體系中,主要使用的有兩種?.NETflix的Ribbon以及官方推出的LoadBalancer。本文OpenFeign與Ribbon協(xié)同工作的核心流程及源碼分析。

使用篇

更換內(nèi)置策略

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

策略UML圖

Ribbon 通過實現(xiàn)IRule接口,內(nèi)置了多種負載均衡的策略,默認采用的是 RoundRobinRule,即輪詢策略。項目中,服務(wù)節(jié)點的部署可能存在基礎(chǔ)配置、網(wǎng)絡(luò)環(huán)境等的差異,抑或是功能上線需要灰度測試,因此,輪詢策略往往不能滿足實際需求。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

ribbon內(nèi)置策略

通過修改消費者工程的配置文件,或修改消費者的啟動類或 JAVAConfig 類可以實現(xiàn)更換負載均衡策略的目的。

方式一,修改配置文件

修改配置文件,在其中添加如下內(nèi)容,指定要使用的負載均衡策略 <clientName>. <clientConfigNameSpace>.NFLoadBalancerRuleClassName。【注:clientName是指服務(wù)提供者的服務(wù)名稱】

該方式的好處是,可以為不同的微服務(wù)指定相應(yīng)的負載均衡策略。

xxx-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
  • 1.
  • 2.
  • 3.

方式二,修改JavaConfig類

在 JavaConfig 類中添加負載 Bean 方法。全局所有feign對應(yīng)服務(wù)都可以生效。

@Configuration
public class FeignConfiguration {
    /**
     * 配置隨機的負載均衡策略
     * 特點:對所有的服務(wù)都生效
     */
    @Bean
    public IRule loadBalancedRule() {
        return new RandomRule();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

自定義負載均衡策略

如果上述的策略不滿足自身要求,我們還可以自定義負載均衡策略。需要操作 2 個步驟:

第一步,集成 AbstractLoadBalancerRule類,AbstractLoadBalancerRule實現(xiàn)了IRule 中的 setLoadBalancer 和 getLoadBalancer,通過繼承 AbstractLoadBalancerRule ,我們就不需要在自己實現(xiàn)這兩個方法,而是把關(guān)注點放在choose方法上,即只關(guān)注如何進行服務(wù)的負載上。

/**
 * 自定義負載均衡算法
 */
public class CustomRule extends AbstractLoadBalancerRule {

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // 基本上不需要實現(xiàn)
    }

    @Override
    public Server choose(Object key) {
        // 實現(xiàn)自己的負載均衡算法
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

第二步,修改JavaConfig類,使用自定義的負載均衡策略:

@Configuration
public class FeignConfiguration {
    @Bean
    public IRule loadBalancedRule() {
        return new CustomRule();
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

或者修改配置文件(Application.properties 或 application.yml):

xxx:
  ribbon:
    NFLoadBalancerRuleClassName: com.xiaopeng.ribbon.CustomRule
  • 1.
  • 2.
  • 3.

Ribbon 核心組件

Ribbon 主要有五大功能組件:ServerList、Rule、Ping、ServerListFilter、ServerListUpdater。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

Ribbon 核心組件

(1)負載均衡器 LoadBalancer

用于管理負載均衡的組件。初始化的時候通過加載 YMAL 配置文件創(chuàng)建出來的。

(2)服務(wù)列表 ServerList

ServerList 主要用來獲取所有服務(wù)的地址信息,并存到本地。根據(jù)獲取服務(wù)信息的方式不同,又分為靜態(tài)存儲和動態(tài)存儲。

  • 靜態(tài)存儲:從配置文件中獲取服務(wù)節(jié)點列表并存儲到本地。
  • 動態(tài)存儲:從注冊中心獲取服務(wù)節(jié)點列表并存儲到本地

(3)服務(wù)列表過濾 ServerListFilter

將獲取到的服務(wù)列表按照過濾規(guī)則過濾。

  • 通過 Eureka 的分區(qū)規(guī)則對服務(wù)實例進行過濾。
  • 比較服務(wù)實例的通信失敗數(shù)和并發(fā)連接數(shù)來剔除不夠健康的實例。
  • 根據(jù)所屬區(qū)域過濾出同區(qū)域的服務(wù)實例。

(4)服務(wù)列表更新 ServerListUpdater

服務(wù)列表更新就是 Ribbon 會從注冊中心獲取最新的注冊表信息。是由這個接口 ServerListUpdater 定義的更新操作。而它有兩個實現(xiàn)類,也就是有兩種更新方式:

  • 通過定時任務(wù)進行更新。由這個實現(xiàn)類 PollingServerListUpdater 做到的。
  • 利用 Eureka 的事件監(jiān)聽器來更新。由這個實現(xiàn)類 EurekaNotificationServerListUpdater 做到的。

(5)心跳檢測 Ping

IPing 接口類用來檢測哪些服務(wù)可用。如果不可用了,就剔除這些服務(wù)。實現(xiàn)類主要有這幾個:PingUrl、PingConstant、NoOpPing、DummyPing、NIWSDiscoveryPing。

心跳檢測策略對象 IPingStrategy,默認實現(xiàn)是輪詢檢測。

(6)負載均衡策略 Rule

源碼分析

我們知道,如果要使用OpenFeign,需要在項目的啟動類增加@EnableFeignClinets注解,接口定義增加@FeignClient注解,這樣一來,@EnableFeignClinets會掃描出每個加了@FeignClient注解的接口,然后生成對應(yīng)的BeanDefinition,最后重新生成一個bean class為FeignClientFactoryBean的BeanDefinition,注冊到spring容器。接下來就會根據(jù)BeanDefinition來生成feign客戶端的代理對象。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

Feign代理對象生成過程

生成代理對象后,所有的方法調(diào)用的時候最終都會走InvocationHandler接口的實現(xiàn),默認就是ReflectiveFeign.FeignInvocationHandler。而我們今天要重點分析的就是,F(xiàn)eignInvocationHandler是如何實現(xiàn)遠程及負載均衡的。

Feign動態(tài)代理調(diào)用實現(xiàn)rpc流程分析

FeignInvocationHandler對于invoke方法的實現(xiàn)。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

前幾個if判斷很簡單,就是判斷是不是調(diào)用的方法是不是equals,hashCode,toString,因為這些方法的調(diào)是不需要走rpc調(diào)用的。

接下就是從dispatch獲取要調(diào)用的方法對應(yīng)的MethodHandler,然后調(diào)用MethodHandler的invoke方法。那MethodHandler是什么時候生成的呢?MethodHandler是在構(gòu)建動態(tài)代理的時候生成的。那MethodHandler作用是什么呢?你可以理解為最終rpc的調(diào)用都是基于這個MethodHandler來實現(xiàn)的,每個方法都有對應(yīng)MethodHandler來實現(xiàn)rpc調(diào)用,接下來我們就來看一下MethodHandler的invoke方法的實現(xiàn)。

MethodHandler是個接口,有兩個實現(xiàn)類,一個是DefaultMethodHandler,這個是處理接口中的默認方法的,另一個是SynchronousMethodHandler,這個是實現(xiàn)rpc調(diào)用的方法。接下來我們就看看SynchronousMethodHandler關(guān)于invoke方法的實現(xiàn)。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

第一行通過方法的參數(shù)構(gòu)建了一個RequestTemplate,RequestTemplate可以看成是組裝http請求所需各種參數(shù)的封裝,比如什么情頭,body之類的都放在這里面。

第二行 Options options = findOptions(argv); 這個很有意思,Options主要是封裝了發(fā)送請求是連接超時時間和讀超時時間的配置,findOptions(argv)也就是先從參數(shù)里面找有沒有Options,沒有就返回構(gòu)造SynchronousMethodHandler的入?yún)r的Options,也就是說,連接超時時間和讀超時時間可以從方法入?yún)韨魅耄贿^一般沒有人這么玩。

第三行就是搞一個重試的組件,是可以實現(xiàn)重試的,一般不設(shè)置。

然后執(zhí)行到executeAndDecode(template, options),進入這個方法。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

首先調(diào)用了targetRequest方法:

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

這個方法會遍歷所有的攔截器RequestInterceptor,這是feign的一個擴展點,也就說在發(fā)送請求前,仍然還有機會對請求的內(nèi)容進行調(diào)整,比如說加個請求頭,這也是很常見的一種方式,在微服務(wù)之間鑒權(quán)的時候使用。RequestInterceptor是在構(gòu)建Feign.Builder的時候傳進來的,F(xiàn)eign.Builder的組件都是通過ioc容器獲取的,組件又是通過配置類來的,所以你需要的話就可以在配置類中聲明RequestInterceptor對象。配置類有不同的優(yōu)先級,按照自己的需求,可以在其中一個優(yōu)先級使用,不過一般這種通用的東西,不是某個微服務(wù)特有的功能,一般選擇在springboot啟動中的容器中配置。

執(zhí)行完targetRequest,回到executeAndDecode之后,會構(gòu)建出一個Request,Request很好理解,就是一個請求,里面封裝了http請求的東西。接下來就會調(diào)用Client的execute方法來執(zhí)行請求,拿到響應(yīng),接下來就是基于處理這個響應(yīng),將響應(yīng)數(shù)據(jù)封裝成需要返回的參數(shù),之后返回給調(diào)用方。

到這里,我們已經(jīng)分析出接口的動態(tài)代理是如何運行的。其實就是通過每個方法對應(yīng)的MethodHandler來實現(xiàn)的,MethodHandler主要就是拼接各種參數(shù),組裝成一個請求,隨后交由Client接口的實現(xiàn)去發(fā)送請求。

LoadBalancerFeignClient

通過上面分析整個動態(tài)代理調(diào)用過程可以看出,Client是發(fā)送http請求的關(guān)鍵類。那么Client是什么玩意?當Feign客戶端在構(gòu)建動態(tài)代理的時候,填充很多組件到Feign.Builder中,其中有個組件就是Client的實現(xiàn),我們并沒有在FeignClientsConfiguration配置類中找到關(guān)于Client的對象的聲明。這個組件的實現(xiàn)是要依賴負載均衡的,也就是這個組件是Feign用來整合Ribbon的入口。

接下來,我們就著重看一下Client的實現(xiàn),看看Feign是如何通過ribbon實現(xiàn)負載均衡的。

我們先來看一下Feign跟ribbon整合的配置類。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

我們來分析一下,首先通過@Impot注解導(dǎo)入了三個配置類。

  • HttpClientFeignLoadBalancedConfiguration:基于HttpClient實現(xiàn)http調(diào)用的。
  • OkHttpFeignLoadBalancedConfiguration:基于OkHttp實現(xiàn)http調(diào)用的。
  • DefaultFeignLoadBalancedConfiguration:默認的,也就是Feign原生的發(fā)送http的實現(xiàn)。

這里我們看一下DefaultFeignLoadBalancedConfiguration配置類,因為默認就是它,HttpClientFeignLoadBalancedConfiguration和OkHttpFeignLoadBalancedConfiguration都需要有引入HttpClient和OkHttp依賴才會有用。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

這個配置類很簡單,聲明了LoadBalancerFeignClient到spring容器,傳入了三個參數(shù),一個Client的實現(xiàn),一個
CachingSpringLoadBalancerFactory和一個SpringClientFactory。LoadBalancerFeignClient這個類實現(xiàn)了Client接口,也就數(shù)說我們在構(gòu)建Feign.Builder填充的就是這個對象,也就是上面說feign的執(zhí)行流程最后用來執(zhí)行請求的Client的實現(xiàn)。

接下來我說一下入?yún)⒌娜齻€參數(shù)是什么意思。

  • Client.Default:就是Feign自己實現(xiàn)的Client,里面封裝了真正發(fā)送http發(fā)送請求的功能,LoadBalancerFeignClient雖然也實現(xiàn)了Client接口,但是這個實現(xiàn)其實是為了整合Ribbon用的,并沒有發(fā)送http的功能,所以需要有個可以發(fā)送http功能的實現(xiàn)。
  • CachingSpringLoadBalancerFactory:后面會說這個類的作用
  • SpringClientFactory:這個跟Feign里面的FeignContext的作用差不多,用來實現(xiàn)配置隔離的,當然,這個也在關(guān)于Ribbon的那篇文章有剖析過。
  • 其實大家可以自行去看OkHttpFeignLoadBalancedConfiguration和HttpClientFeignLoadBalancedConfiguration,其實他們配置跟DefaultFeignLoadBalancedConfiguration是一樣的,聲明的對象都是LoadBalancerFeignClient,只不過將Client.Default換成了基于HttpClient和OkHttp的實現(xiàn),也就是發(fā)送http請求使用的工具不一樣。

FeignRibbonClientAutoConfiguration除了導(dǎo)入配置類還聲明了CachingSpringLoadBalancerFactory,只不過一種是帶基于spring實現(xiàn)的重試功能的,一種是不帶的,主要看有沒有引入spring重試功能的包,所以上面構(gòu)建LoadBalancerFeignClient注入的CachingSpringLoadBalancerFactory就是在這聲明的。

這里就說完了Feign整合ribbon的配置類
FeignRibbonClientAutoConfiguration,我們也找到了構(gòu)造Feign.Builder的實現(xiàn)LoadBalancerFeignClient,接下來就來剖析LoadBalancerFeignClient的實現(xiàn)。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

在動態(tài)代理調(diào)用的那里我們得出一個結(jié)論,那就是最后會調(diào)用Client接口的execute方法的實現(xiàn),所以我們就看一下execute方法的實現(xiàn),這里就是一堆操作,從請求的URL中拿到了clientName,也就是服務(wù)名。

為什么可以拿到服務(wù)名?

其實很簡單,OpenFeign構(gòu)建動態(tài)代理的時候,傳入了一個HardCodedTarget,當時說在構(gòu)建HardCodedTarget的時候傳入了一個url,那個url當時說了其實就是http://服務(wù)名,所以到這里,雖然有具體的請求接口的路徑,但是還是類似 http://服務(wù)名/api/sayHello這種,所以可以通過路徑拿到你鎖請求的服務(wù)名。

拿到服務(wù)名之后,再拿到了一個配置類IClientConfig,最后調(diào)用lbClient,我們看一下lbClient的方法實現(xiàn)。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

就是調(diào)用CachingSpringLoadBalancerFactory的create方法。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

這個方法先根據(jù)服務(wù)名從緩存中獲取一個FeignLoadBalancer,獲取不到就創(chuàng)建一個。

創(chuàng)建的過程就是從每個服務(wù)對應(yīng)的容器中獲取到IClientConfig和ILoadBalancer。Ribbon那篇文章都講過這些核心類,這里不再贅述。

默認就是創(chuàng)建不帶spring重試功能的FeignLoadBalancer,放入緩存,最后返回這個FeignLoadBalancer。所以第一次來肯定沒有,需要構(gòu)建,也就是最終一定會返回FeignLoadBalancer,所以我們通過lbClient方法拿到的是FeignLoadBalancer。從這里可以看出
CachingSpringLoadBalancerFactory是構(gòu)建FeignLoadBalancer的工廠類,只不過先從緩存中查找,找不到再創(chuàng)建FeignLoadBalancer。

拿到FeignLoadBalancer之后就會調(diào)用executeWithLoadBalancer,接收到Response之后直接返回。

FeignLoadBalancer

那么這個FeignLoadBalancer又是啥呢?這里放上FeignLoadBalancer核心源碼。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

FeignLoadBalancer繼承自AbstractLoadBalancerAwareClient,AbstractLoadBalancerAwareClient又是啥玩意?看過我寫的關(guān)于Ribbon核心組件已經(jīng)運行原理的那篇文章小伙伴肯定知道,AbstractLoadBalancerAwareClient類主要作用是通過ILoadBalancer組件獲取一個Server,然后基于這個Server重構(gòu)了URI,也就是將你的請求路徑http://服務(wù)名/api/sayHello轉(zhuǎn)換成類似http://192.168.1.101:8088/api/sayHello這種路徑,也就是將原服務(wù)名替換成服務(wù)所在的某一臺機器ip和端口,替換之后就交由子類實現(xiàn)的exceut方法來發(fā)送http請求。

所以我們知道調(diào)用executeWithLoadBalancer之后,就會重構(gòu)請求路徑,將服務(wù)名替換成某個具體的服務(wù)器所在的ip和端口,之后交給子類execute來處理,對于這里來說,也就是FeignLoadBalancer的execute方法,因為FeignLoadBalancer繼承
AbstractLoadBalancerAwareClient。

直接定位到execute方法最核心的一行代碼。

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

request.client()就會拿到構(gòu)建LoadBalancerFeignClient傳入的那個Client的實現(xiàn),我提到過,這個Client的實現(xiàn)是具體發(fā)送請求的實現(xiàn),默認的就是Client.Default類(不是默認就有可能是基于HttpClient或者是OkHttp的實現(xiàn))。所以這行代碼就是基于這個Client就成功的發(fā)送了Http請求,拿到響應(yīng),然后將這個Response 封裝成一個RibbonResponse返回,最后就返回給MethodHandler,然后解析響應(yīng),封裝成方法的返回值返回給調(diào)用者。

好了,其實到這里就完全知道Feign是如何整合Ribbon的,LoadBalancerFeignClient其實是OpenFeign適配Ribbon的入口,F(xiàn)eignLoadBalancer才是真正實現(xiàn)選擇負載均衡,發(fā)送http請求的組件,因為他繼承了
AbstractLoadBalancerAwareClient。

整個動態(tài)代理的調(diào)用過程:

 

SpringCloud OpenFeign整合Ribbon實現(xiàn)負載均衡及源碼分析

通過這張圖,我們可以清楚地看出OpenFeign、Ribbon以及注冊中心之間的協(xié)同關(guān)系。

總結(jié)

OpenFeign在進行rpc調(diào)用的時候,由于不知道服務(wù)具體在哪臺機器上,所以需要Ribbon這個負載均衡組件從服務(wù)所在的機器列表中選擇一個,Ribbon中服務(wù)所在的機器列表是從注冊中心拉取的,Ribbon提供了一個ServerList接口,注冊中心實現(xiàn)之后,Ribbon就可以獲取到服務(wù)所在的機器列表,這就是這三個組件最基本的原理。

參考&鳴謝

https://www.cnblogs.com/zzyang/p/16404783.html

分享到:
標簽:SpringCloud
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定