日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

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

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

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

使用篇

更換內置策略

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

策略UML圖

Ribbon 通過實現IRule接口,內置了多種負載均衡的策略,默認采用的是 RoundRobinRule,即輪詢策略。項目中,服務節點的部署可能存在基礎配置、網絡環境等的差異,抑或是功能上線需要灰度測試,因此,輪詢策略往往不能滿足實際需求。

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

ribbon內置策略

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

方式一,修改配置文件

修改配置文件,在其中添加如下內容,指定要使用的負載均衡策略 <clientName>. <clientConfigNameSpace>.NFLoadBalancerRuleClassName?!咀ⅲ篶lientName是指服務提供者的服務名稱】

該方式的好處是,可以為不同的微服務指定相應的負載均衡策略。

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

方式二,修改JavaConfig類

在 JavaConfig 類中添加負載 Bean 方法。全局所有feign對應服務都可以生效。

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

自定義負載均衡策略

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

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

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

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

    @Override
    public Server choose(Object key) {
        // 實現自己的負載均衡算法
    }
}
  • 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實現負載均衡及源碼分析

Ribbon 核心組件

(1)負載均衡器 LoadBalancer

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

(2)服務列表 ServerList

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

  • 靜態存儲:從配置文件中獲取服務節點列表并存儲到本地。
  • 動態存儲:從注冊中心獲取服務節點列表并存儲到本地

(3)服務列表過濾 ServerListFilter

將獲取到的服務列表按照過濾規則過濾。

  • 通過 Eureka 的分區規則對服務實例進行過濾。
  • 比較服務實例的通信失敗數和并發連接數來剔除不夠健康的實例。
  • 根據所屬區域過濾出同區域的服務實例。

(4)服務列表更新 ServerListUpdater

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

  • 通過定時任務進行更新。由這個實現類 PollingServerListUpdater 做到的。
  • 利用 Eureka 的事件監聽器來更新。由這個實現類 EurekaNotificationServerListUpdater 做到的。

(5)心跳檢測 Ping

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

心跳檢測策略對象 IPingStrategy,默認實現是輪詢檢測。

(6)負載均衡策略 Rule

源碼分析

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

Feign代理對象生成過程

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

Feign動態代理調用實現rpc流程分析

FeignInvocationHandler對于invoke方法的實現。

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

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

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

第二行 Options options = findOptions(argv); 這個很有意思,Options主要是封裝了發送請求是連接超時時間和讀超時時間的配置,findOptions(argv)也就是先從參數里面找有沒有Options,沒有就返回構造SynchronousMethodHandler的入參時的Options,也就是說,連接超時時間和讀超時時間可以從方法入參來傳入,不過一般沒有人這么玩。

第三行就是搞一個重試的組件,是可以實現重試的,一般不設置。

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

首先調用了targetRequest方法:

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

執行完targetRequest,回到executeAndDecode之后,會構建出一個Request,Request很好理解,就是一個請求,里面封裝了http請求的東西。接下來就會調用Client的execute方法來執行請求,拿到響應,接下來就是基于處理這個響應,將響應數據封裝成需要返回的參數,之后返回給調用方。

到這里,我們已經分析出接口的動態代理是如何運行的。其實就是通過每個方法對應的MethodHandler來實現的,MethodHandler主要就是拼接各種參數,組裝成一個請求,隨后交由Client接口的實現去發送請求。

LoadBalancerFeignClient

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

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

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

  • HttpClientFeignLoadBalancedConfiguration:基于HttpClient實現http調用的。
  • OkHttpFeignLoadBalancedConfiguration:基于OkHttp實現http調用的。
  • DefaultFeignLoadBalancedConfiguration:默認的,也就是Feign原生的發送http的實現。

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

接下來我說一下入參的三個參數是什么意思。

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

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

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

為什么可以拿到服務名?

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

拿到服務名之后,再拿到了一個配置類IClientConfig,最后調用lbClient,我們看一下lbClient的方法實現。

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

就是調用CachingSpringLoadBalancerFactory的create方法。

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

這個方法先根據服務名從緩存中獲取一個FeignLoadBalancer,獲取不到就創建一個。

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

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

拿到FeignLoadBalancer之后就會調用executeWithLoadBalancer,接收到Response之后直接返回。

FeignLoadBalancer

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

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

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

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

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

整個動態代理的調用過程:

 

SpringCloud OpenFeign整合Ribbon實現負載均衡及源碼分析

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

總結

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

參考&鳴謝

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

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

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

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

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

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

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定