欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?Cloud?Ribbon的使用原理解析

 更新時(shí)間:2022年07月20日 11:32:40   作者:怪?咖@  
現(xiàn)在Java非常流行微服務(wù),也就是所謂的面向服務(wù)開(kāi)發(fā),將一個(gè)項(xiàng)目拆分成了多個(gè)項(xiàng)目,其優(yōu)點(diǎn)有很多,其中一個(gè)優(yōu)點(diǎn)就是:將服務(wù)拆分成一個(gè)一個(gè)微服務(wù)后,我們很容易的來(lái)針對(duì)性的進(jìn)行集群部署,這篇文章主要介紹了Spring?Cloud?Ribbon的使用詳解,需要的朋友可以參考下

一、概述

1、Ribbon是什么

Ribbon是Netflix發(fā)布的開(kāi)源項(xiàng)目,Spring Cloud Ribbon是基于Netflix Ribbon實(shí)現(xiàn)的一套客戶端負(fù)載均衡的框架。

2、Ribbon能干什么

LB負(fù)載均衡(Load Balance)是什么?

簡(jiǎn)單的說(shuō)就是將用戶的請(qǐng)求平攤的分配到多個(gè)服務(wù)上,從而達(dá)到系統(tǒng)的HA(高可用)。
常見(jiàn)的負(fù)載均衡有軟件Nginx,硬件 F5等。

什么情況下需要負(fù)載均衡?

現(xiàn)在Java非常流行微服務(wù),也就是所謂的面向服務(wù)開(kāi)發(fā),將一個(gè)項(xiàng)目拆分成了多個(gè)項(xiàng)目,其優(yōu)點(diǎn)有很多,其中一個(gè)優(yōu)點(diǎn)就是:將服務(wù)拆分成一個(gè)一個(gè)微服務(wù)后,我們很容易的來(lái)針對(duì)性的進(jìn)行集群部署。例如訂單模塊用的人比較多,我就可以將這個(gè)模塊多部署幾臺(tái)機(jī)器,來(lái)分擔(dān)單個(gè)服務(wù)器的壓力。

這時(shí)候有個(gè)問(wèn)題來(lái)了,前端頁(yè)面請(qǐng)求的時(shí)候到底請(qǐng)求集群當(dāng)中的哪一臺(tái)?既然是降低單個(gè)服務(wù)器的壓力,所以肯定全部機(jī)器都要利用起來(lái),而不是說(shuō)一臺(tái)用著,其他空余著。這時(shí)候就需要用負(fù)載均衡了,像這種前端頁(yè)面調(diào)用后端請(qǐng)求的,要做負(fù)載均衡的話,常用的就是Nginx。

Ribbon和Nginx負(fù)載均衡區(qū)別

  • 當(dāng)后端服務(wù)是集群的情況下,前端頁(yè)面調(diào)用后端請(qǐng)求,要做負(fù)載均衡的話,常用的就是Nginx。
  • Ribbon主要是在服務(wù)端內(nèi)做負(fù)載均衡,舉例:訂單后端服務(wù) 要調(diào)用 支付后端服務(wù),這屬于后端之間的服務(wù)調(diào)用,壓根根本不經(jīng)過(guò)頁(yè)面,而支付后端服務(wù)是集群,這時(shí)候訂單服務(wù)就需要做負(fù)載均衡來(lái)調(diào)用支付服務(wù),記住是訂單服務(wù)做負(fù)載均衡 來(lái)調(diào)用 支付服務(wù)。

負(fù)載均衡分類(lèi)

  • 集中式LB:即在服務(wù)的消費(fèi)方和提供方之間使用獨(dú)立的LB設(shè)施(可以是硬件,如F5, 也可以是軟件,如nginx),由該設(shè)施負(fù)責(zé)把訪問(wèn)請(qǐng)求通過(guò)某種策略轉(zhuǎn)發(fā)至服務(wù)的提供方;
  • 進(jìn)程內(nèi)LB:將LB邏輯集成到消費(fèi)方,消費(fèi)方從服務(wù)注冊(cè)中心獲知有哪些地址可用,然后自己再?gòu)倪@些地址中選擇出一個(gè)合適的服務(wù)器。

Ribbon負(fù)載均衡

Ribbon就屬于進(jìn)程內(nèi)LB,它只是一個(gè)類(lèi)庫(kù),集成于消費(fèi)方進(jìn)程。

舉例:微服務(wù)經(jīng)常會(huì)涉及到A服務(wù)調(diào)用B服務(wù)的接口,這時(shí)候就需要用HTTP遠(yuǎn)程調(diào)用框架,常見(jiàn)的有Feign、RestTemplate、HttpClient,假如B服務(wù)只有一個(gè)節(jié)點(diǎn),這時(shí)候我們可以在調(diào)用的時(shí)候?qū)懝潭╥p來(lái)進(jìn)行調(diào)用,假如B服務(wù)的節(jié)點(diǎn)存在多個(gè)(也就是集群),那A服務(wù)究竟調(diào)用B服務(wù)的哪個(gè)節(jié)點(diǎn)呢,這時(shí)候可以通過(guò)負(fù)載均衡框架來(lái)計(jì)算出調(diào)用哪個(gè),比如輪詢調(diào)用B服務(wù)的多個(gè)節(jié)點(diǎn),總不可能一直調(diào)用人家的一個(gè)服務(wù),這樣B服務(wù)的集群有什么意義呢?或者也可以隨機(jī)調(diào)用任意節(jié)點(diǎn),總之負(fù)載均衡的作用就是避免一直調(diào)用一個(gè)節(jié)點(diǎn)。

大概的流程:RestTemplate或者Feign可以通過(guò)注冊(cè)中心拿到服務(wù)提供方的IP+端口,假如提供者有多個(gè),那他就會(huì)拿到多個(gè)地址,有了這些地址就差訪問(wèn)的時(shí)候訪問(wèn)哪個(gè)地址的服務(wù)了,而Ribbon可以很好的和RestTemplate或者Feign進(jìn)行集成,來(lái)決定調(diào)用哪個(gè)服務(wù),具體是負(fù)載均衡還是隨機(jī)Ribbon都可以設(shè)置。

3、Ribbon現(xiàn)狀

項(xiàng)目處于維護(hù)狀態(tài) ,已經(jīng)一年多沒(méi)有更新過(guò)了。

https://github.com/Netflix/ribbon

4、未來(lái)替代方案

5、架構(gòu)說(shuō)明

首先通過(guò)上圖一定要明白一點(diǎn):ribbon一定是用在消費(fèi)方,而不是服務(wù)的提供方!

Ribbon在工作時(shí)分成兩步(這里以Eureka為例,consul和zk同樣道理):

  • 第一步先選擇 EurekaServer ,它優(yōu)先選擇在同一個(gè)區(qū)域內(nèi)負(fù)載較少的server.
  • 第二步再根據(jù)用戶指定的策略,在從server取到的服務(wù)注冊(cè)列表中選擇一個(gè)地址。

其中Ribbon提供了多種策略:比如輪詢、隨機(jī)和根據(jù)響應(yīng)時(shí)間加權(quán)。

Spring Cloud Eureka服務(wù)注冊(cè)中心入門(mén)流程分析

http://www.dbjr.com.cn/article/204240.htm

之前寫(xiě)樣例時(shí)候沒(méi)有引入spring-cloud-starter-ribbon也可以使用ribbon,這是為什么?

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

猜測(cè)spring-cloud-starter-netflix-eureka-client自帶了spring-cloud-starter-ribbon引用

證明如下: 可以看到spring-cloud-starter-netflix-eureka-client 確實(shí)引入了Ribbon(zk和consul注冊(cè)中心同樣是如此)

二、RestTemplate 用法詳解

本篇涉及到的項(xiàng)目均使用RestTemplate結(jié)合Ribbon來(lái)完成遠(yuǎn)程負(fù)載均衡調(diào)用!

RestTemplate 用法詳解:http://www.dbjr.com.cn/article/256124.htm

三、Ribbon核心組件IRule

IRule:根據(jù)特定算法中從服務(wù)列表中選取一個(gè)要訪問(wèn)的服務(wù)

Ribbon給提供了很多現(xiàn)成的算法類(lèi),IRule就是最頂層的算法類(lèi)接口,Ribbon默認(rèn)是輪詢規(guī)則。假如我們想要修改算法,只需要將算法類(lèi)注入到容器。然后通過(guò)簡(jiǎn)單的配置就可以修改。

這些算法類(lèi)都在如下包當(dāng)中,一般我們只要引入Eureka、zk、consul三個(gè)其中一個(gè)注冊(cè)中心的依賴,就會(huì)附帶Ribbon的依賴,Ribbon依賴就會(huì)依賴ribbon-loadbalancer包。

  • ClientConfigEnabledRoundRobinRule:該策略較為特殊,我們一般不直接使用它。因?yàn)樗旧聿](méi)有實(shí)現(xiàn)什么特殊的處理邏輯。一般都是可以通過(guò)繼承他重寫(xiě)一些自己的策略,默認(rèn)的choose方法就實(shí)現(xiàn)了線性輪詢機(jī)制
  • BestAvailableRule:繼承自ClientConfigEnabledRoundRobinRule,會(huì)先過(guò)濾掉由于多次訪問(wèn)故障而處于斷路器跳閘狀態(tài)的服務(wù),然后選擇一個(gè)并發(fā)量最小的服務(wù),該策略的特性是可選出最空閑的實(shí)例
  • PredicateBasedRule:繼承自ClientConfigEnabledRoundRobinRule,抽象策略,需要重寫(xiě)方法的,然后自己來(lái)自己定義過(guò)濾規(guī)則的
  • AvailabilityFilteringRule:繼承PredicateBasedRule,先過(guò)濾掉故障實(shí)例,再選擇并發(fā)較小的實(shí)例
  • ZoneAvoidanceRule:繼承PredicateBasedRule,默認(rèn)規(guī)則,復(fù)合判斷server所在區(qū)域的性能和server的可用性選擇服務(wù)器
  • com.netflix.loadbalancer.RoundRobinRule:輪詢
  • WeightedResponseTimeRule:對(duì)RoundRobinRule的擴(kuò)展,響應(yīng)速度越快的實(shí)例選擇權(quán)重越大,越容易被選擇
  • ResponseTimeWeightedRule:對(duì)RoundRobinRule的擴(kuò)展,響應(yīng)時(shí)間加權(quán)
  • com.netflix.loadbalancer.RandomRule:隨機(jī)
  • com.netflix.loadbalancer.StickyRule:這個(gè)基本也沒(méi)人用
  • com.netflix.loadbalancer.RetryRule:先按照RoundRobinRule的策略獲取服務(wù),如果獲取服務(wù)失敗則在指定時(shí)間內(nèi)會(huì)進(jìn)行重試,獲取可用的服務(wù)
  • ZoneAvoidanceRule:默認(rèn)規(guī)則,復(fù)合判斷server所在區(qū)域的性能和server的可用性選擇服務(wù)器

四、實(shí)戰(zhàn)項(xiàng)目

1、回顧之前的項(xiàng)目

http://www.dbjr.com.cn/article/204240.htm

如下是項(xiàng)目當(dāng)中涉及到的微服務(wù):

ribbon一定是用在消費(fèi)端,A調(diào)用B服務(wù)的接口,那么A就是消費(fèi)端

在這個(gè)項(xiàng)目示例當(dāng)中,在消費(fèi)者服務(wù)當(dāng)中通過(guò)RestTemplate+@LoadBalanced來(lái)完成負(fù)載均衡調(diào)用提供者。

這里調(diào)用提供者的時(shí)候不再是固定ip,而是通過(guò)服務(wù)名稱調(diào)用。相當(dāng)于通過(guò)服務(wù)名稱向注冊(cè)中心當(dāng)中去獲取注冊(cè)的服務(wù),假如注冊(cè)了兩個(gè)名稱一樣的服務(wù),那么就獲取到了兩個(gè)ip,RestTemplate內(nèi)部控制了訪問(wèn)哪個(gè)ip的服務(wù)。他是如何負(fù)載均衡的?就是和Ribbon無(wú)縫結(jié)合,具體原理后續(xù)再說(shuō)。

注意:RestTemplate想要通過(guò)服務(wù)名稱來(lái)調(diào)用,那么一定要配置@LoadBalanced注解,不然會(huì)報(bào)錯(cuò)的,只有配置了這個(gè)注解,RestTemplate才會(huì)和Ribbon相結(jié)合。

服務(wù)名稱就是在提供者的application當(dāng)中配置的。

2、@RibbonClient注解用法

這個(gè)注解的意思就是,當(dāng)RestTemplate調(diào)用服務(wù)名稱為CLOUD-PAYMENT-SERVICE的時(shí)候,采用MySelfRule當(dāng)中注入的負(fù)載均衡算法。

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration=MySelfRule.class)

官方文檔明確給出了警告:這個(gè)自定義配置類(lèi)不能放在@ComponentScan所掃描的當(dāng)前包下以及子包下,否則我們自定義的這個(gè)配置類(lèi)就會(huì)被所有的Ribbon客戶端所共享,達(dá)不到特殊化定制的目的了(也就是一旦被掃描到,RestTemplate直接不管調(diào)用哪個(gè)服務(wù)都會(huì)用指定的算法)。

springboot項(xiàng)目當(dāng)中的啟動(dòng)類(lèi)使用了@SpringBootApplication注解,這個(gè)注解內(nèi)部就有@ComponentScan注解,默認(rèn)是掃描啟動(dòng)類(lèi)包下所有的包,所以我們要達(dá)到定制化一定不要放在他能掃描到的地方。

cloud中文官網(wǎng):https://www.springcloud.cc/spring-cloud-greenwich.html#netflix-ribbon-starter

3、配置文件用法

如下配置就可以取代@RibbonClient注解,注意一定要使用全類(lèi)名,沒(méi)有@RibbonClient級(jí)別高:

CLOUD-PAYMENT-SERVICE:
  ribbon:
    NFLoadBalancerRuleClassName: com.gzl.myrule.MySelfRule
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration=MySelfRule.class)

4、修改默認(rèn)算法

我們還是基于這個(gè)Eureka項(xiàng)目示例來(lái)進(jìn)行演示修改默認(rèn)算法::http://www.dbjr.com.cn/article/204240.htm

1. 修改cloud-consumer-order80(ribbon一定是用在消費(fèi)端,A調(diào)用B服務(wù)的接口,那么A就是消費(fèi)端)

新建package,只要不和啟動(dòng)類(lèi)在同一個(gè)包下即可!

@Configuration
public class MySelfRule {
    @Bean
    public IRule myRule() {
        //定義為隨機(jī)
        return new RandomRule();
    }
}

2、主啟動(dòng)類(lèi)添加@RibbonClient(這個(gè)是一定要指定的,不然他不知道我們要修改算法,假如配置文件方式指定了就不需要添加這個(gè)注解了)

在啟動(dòng)該微服務(wù)的時(shí)候就能去加載我們的自定義Ribbon配置類(lèi),從而使配置生效:

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration= MySelfRule.class)

3、測(cè)試

這時(shí)候再測(cè)試訪問(wèn)消費(fèi)者接口,會(huì)發(fā)現(xiàn)已經(jīng)不再是輪詢?cè)L問(wèn)了,成為了隨機(jī)訪問(wèn)!

訪問(wèn):http://localhost/consumer/payment/get/1

五、Ribbon原理

1、負(fù)載均衡算法

以輪詢算法為例:rest接口第幾次請(qǐng)求數(shù) % 服務(wù)器集群總數(shù)量 = 實(shí)際調(diào)用服務(wù)器位置下標(biāo)

每次服務(wù)重啟動(dòng)后rest接口計(jì)數(shù)從1開(kāi)始。

為什么要獲取服務(wù)器下標(biāo)呢?

算法完全是基于DiscoveryClient來(lái)從注冊(cè)中心獲取到注冊(cè)的服務(wù)列表,獲取的是個(gè)List<ServiceInstance>,有了下標(biāo),有了服務(wù)list集合,那我們自然就知道要訪問(wèn)哪個(gè)服務(wù)了。

import org.springframework.cloud.client.discovery.DiscoveryClient;
@Resource
private DiscoveryClient discoveryClient;

List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance element : instances) {
            System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"
                    + element.getUri());
        }

輸出的結(jié)果:

如: List [0] instances = 127.0.0.1:8002
   List [1] instances = 127.0.0.1:8001

8001+ 8002 組合成為集群,它們共計(jì)2臺(tái)機(jī)器,集群總數(shù)為2, 按照輪詢算法原理:

  • 當(dāng)總請(qǐng)求數(shù)為1時(shí): 1 % 2 =1 對(duì)應(yīng)下標(biāo)位置為1 ,則獲得服務(wù)地址為127.0.0.1:8001
  • 當(dāng)總請(qǐng)求數(shù)位2時(shí): 2 % 2 =0 對(duì)應(yīng)下標(biāo)位置為0 ,則獲得服務(wù)地址為127.0.0.1:8002
  • 當(dāng)總請(qǐng)求數(shù)位3時(shí): 3 % 2 =1 對(duì)應(yīng)下標(biāo)位置為1 ,則獲得服務(wù)地址為127.0.0.1:8001
  • 當(dāng)總請(qǐng)求數(shù)位4時(shí): 4 % 2 =0 對(duì)應(yīng)下標(biāo)位置為0 ,則獲得服務(wù)地址為127.0.0.1:8002
  • 如此類(lèi)推…

2、源碼分析

我看的Cloud的Hoxton.SR1版本,版本之間源碼略有不同,但是大概思路差不多。

ribbon實(shí)現(xiàn)的關(guān)鍵點(diǎn)是為ribbon定制的RestTemplate,ribbon利用了RestTemplate的攔截器機(jī)制,在攔截器中實(shí)現(xiàn)ribbon的負(fù)載均衡。負(fù)載均衡的基本實(shí)現(xiàn)就是利用applicationName從服務(wù)注冊(cè)中心獲取可用的服務(wù)地址列表,然后通過(guò)一定算法負(fù)載,決定使用哪一個(gè)服務(wù)地址來(lái)進(jìn)行http調(diào)用。

1.Ribbon的RestTemplate

RestTemplate中有一個(gè)屬性是List<ClientHttpRequestInterceptor> interceptors,如果interceptors里面的攔截器數(shù)據(jù)不為空,在RestTemplate進(jìn)行http請(qǐng)求時(shí),這個(gè)請(qǐng)求就會(huì)被攔截器攔截進(jìn)行,攔截器需要實(shí)現(xiàn)ClientHttpRequestInterceptor接口,接口就一個(gè)方法,需要實(shí)現(xiàn)以下方法:

也就是說(shuō)攔截器需要完成http請(qǐng)求,并封裝一個(gè)標(biāo)準(zhǔn)的response返回。

2.Ribbon中的攔截器

在Ribbon 中就是通過(guò)名字為LoadBalancerInterceptor的攔截器,注入到RestTemplate中,進(jìn)行攔截請(qǐng)求,然后實(shí)現(xiàn)負(fù)載均衡調(diào)用的。

攔截器定義在:org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration

這個(gè)類(lèi)是在這個(gè)包下,并不在Ribbon的包下:

攔截器的定義與攔截器注入器的定義:下面的bean是攔截器注入器

3.Ribbon中的攔截器注入到RestTemplate

定義了攔截器,自然需要把攔截器注入到、RestTemplate才能生效,那么Ribbon中是如何實(shí)現(xiàn)的?上面說(shuō)了攔截器的定義與攔截器注入器的定義,那么肯定會(huì)有個(gè)地方使用注入器來(lái)注入攔截器的。

還是在這個(gè)類(lèi)當(dāng)中:org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration

遍歷context中的注入器,調(diào)用注入方法,為目標(biāo)RestTemplate注入攔截器,注入器和攔截器都是我們定義好的。

還有關(guān)鍵的一點(diǎn)是:需要注入攔截器的目標(biāo)restTemplates到底是哪一些?因?yàn)?code>RestTemplate實(shí)例在context中可能存在多個(gè),不可能所有的都注入攔截器,這里就是@LoadBalanced注解發(fā)揮作用的時(shí)候了。

4.LoadBalanced注解

嚴(yán)格上來(lái)說(shuō),這個(gè)注解是spring cloud實(shí)現(xiàn)的,不是ribbon中的,它的作用是在依賴注入時(shí),只注入實(shí)例化時(shí)被@LoadBalanced修飾的實(shí)例。

例如我們定義Ribbon的RestTemplate的時(shí)候是這樣的:

@Bean
@LoadBalanced
public RestTemplate rebbionRestTemplate(){
    return new RestTemplate();
}

因此才能為我們定義的RestTemplate注入攔截器。

那么@LoadBalanced是如何實(shí)現(xiàn)這個(gè)功能的呢?其實(shí)都是spring的原生操作,@LoadBalance的源碼如下

@Qualifier注解很重要:

@Autowired默認(rèn)是根據(jù)類(lèi)型進(jìn)行注入的,因此如果有多個(gè)類(lèi)型一樣的Bean候選者,則需要限定其中一個(gè)候選者,否則將拋出異常,@Qualifier限定描述符除了能根據(jù)名字進(jìn)行注入,更能進(jìn)行更細(xì)粒度的控制如何選擇候選者

@LoadBalanced很明顯,‘繼承’了注解@Qualifier,RestTemplates通過(guò)@Autowired注入,同時(shí)被@LoadBalanced修飾,所以只會(huì)注入@LoadBalanced修飾的RestTemplate,也就是我們的目標(biāo)RestTemplate。

5.攔截器邏輯實(shí)現(xiàn)

這里使用的是LoadBalancerInterceptor攔截器

當(dāng)我們每通過(guò)RestTemplate調(diào)用一個(gè)接口的時(shí)候都會(huì)經(jīng)過(guò)這個(gè)攔截器,通過(guò)攔截器當(dāng)中的intercept方法,然后執(zhí)行excute的時(shí)候,打斷點(diǎn)會(huì)發(fā)現(xiàn)他會(huì)執(zhí)行到這:

在這里就是根據(jù)對(duì)應(yīng)的負(fù)載均衡算法選擇對(duì)應(yīng)的服務(wù),RibbonLoadBalancerClient就是Ribbon當(dāng)中的類(lèi)了。由此可以看出框架有時(shí)候就是這樣,來(lái)回套用,cloud對(duì)外提供API,然后組件進(jìn)行真正的實(shí)現(xiàn),假如感覺(jué)ribbon滿足不了我們,我們完全可以按照cloud的API來(lái)開(kāi)發(fā)新的負(fù)載均衡框架,進(jìn)行無(wú)縫替換。

(1)getLoadBalancer(serviceId):可以理解為,再第一次請(qǐng)求到來(lái)時(shí),創(chuàng)建好IClientConfig(客戶端配置)、ServerList(從配置文件中加載的服務(wù)列表)、IRule(負(fù)載均衡策略)與IPing (探活策略)等Bean,是一種懶加載的模式。

(2)getServer(loadBalancer, hint):則是通過(guò)以上的負(fù)載均衡策略與探活策略,從服務(wù)列表中選擇合適的服務(wù)實(shí)例(詳細(xì)代碼在ZoneAwareLoadBalancer的chooseServer方法中)。Server對(duì)象包含ip、端口與協(xié)議等信息。

重點(diǎn)看getServer方法,看看是如何選擇服務(wù)的

默認(rèn)就是ZoneAvoidanceRule負(fù)載均衡算法!

ZoneAvoidanceRule:繼承PredicateBasedRule,他是沒(méi)有重寫(xiě)choose方法的,這時(shí)候就進(jìn)入到了父類(lèi)的choose方法。

public Server choose(Object key) {
   ILoadBalancer lb = getLoadBalancer();
	// 這里就完成了服務(wù)的選擇
	// 而且我們可以看到,這里的lb.getAllServers 說(shuō)明ILoadBalancer直接存儲(chǔ)或者間接存儲(chǔ)了服務(wù)列表
   Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
   if (server.isPresent()) {
       return server.get();
   } else {
       return null;
   }       
}

從上面可以看到chooseRoundRobinAfterFiltering 這個(gè)方法的意思就是在過(guò)濾之后,選擇輪詢的負(fù)載均衡方式。

lb.getAllServers是獲取該服務(wù)的所有服務(wù)實(shí)例。

由此可見(jiàn)chooseRoundRobinAfterFiltering就是選擇的關(guān)鍵點(diǎn)了。

public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
    // 過(guò)濾掉不復(fù)合條件的服務(wù)實(shí)例
	List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
     if (eligible.size() == 0) {
         return Optional.absent();
     }
	// incrementAndGetModulo 這個(gè)就是輪詢的關(guān)鍵計(jì)算
     return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
 }

其計(jì)算過(guò)程還是比較簡(jiǎn)單的,使用了AtomicInteger來(lái)計(jì)算訪問(wèn)的次數(shù),cas+自旋鎖來(lái)控制多線程的安全性!

private final AtomicInteger nextIndex = new AtomicInteger();

六、手寫(xiě)負(fù)載均衡器

1.RestTemplate去掉注解@LoadBalanced

2.LoadBalancer接口(在80消費(fèi)者添加)

這個(gè)接口相當(dāng)于是傳進(jìn)去多個(gè)服務(wù),然后根據(jù)實(shí)現(xiàn)類(lèi),來(lái)選擇出一個(gè)服務(wù),至于是輪詢還是隨機(jī),我們自己實(shí)現(xiàn)。

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

public interface LoadBalancer {
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

3.定義實(shí)現(xiàn)類(lèi)(在80消費(fèi)者添加)

@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    // 獲取服務(wù)的下標(biāo)
    public final int getAndIncrement() {
        int current;
        int next;
        do {
            current = this.atomicInteger.get();
            next = current >= 2147483647 ? 0 : current + 1;
        } while (!this.atomicInteger.compareAndSet(current, next));
        System.out.println("*****next: " + next);
        return next;
    }

    // 下標(biāo)和服務(wù)數(shù)進(jìn)行取模
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

4.調(diào)整8001服務(wù)和8002服務(wù),這兩個(gè)服務(wù)是提供者,新增一個(gè)接口,來(lái)進(jìn)行測(cè)試使用!

@Value("${server.port}")
private String serverPort;

@GetMapping(value = "/payment/lb")
 public String getPaymentLB() {
     return serverPort;
 }

5.在消費(fèi)者80端添加測(cè)試接口

@GetMapping("/consumer/payment/lb")
public String getPaymentLB() {
    // 這個(gè)是利用的cloud自帶的DiscoveryClient,假如cloud項(xiàng)目使用了注冊(cè)中心都可以通過(guò)服務(wù)名稱來(lái)獲取對(duì)應(yīng)的服務(wù)信息
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");

    if (instances == null || instances.size() <= 0) {
        return null;
    }
    // 獲取要訪問(wèn)的服務(wù)信息
    ServiceInstance serviceInstance = loadBalancer.instances(instances);
    URI uri = serviceInstance.getUri();

    return restTemplate.getForObject(uri + "/payment/lb", String.class);
}

6.測(cè)試

http://localhost/consumer/payment/lb

這樣我們就成功自己實(shí)現(xiàn)了一個(gè)負(fù)載均衡!

到此這篇關(guān)于Spring Cloud Ribbon的使用詳解的文章就介紹到這了,更多相關(guān)Spring Cloud Ribbon使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • spring security 5.x實(shí)現(xiàn)兼容多種密碼的加密方式

    spring security 5.x實(shí)現(xiàn)兼容多種密碼的加密方式

    spring security針對(duì)該功能有兩種實(shí)現(xiàn)方式,一種是簡(jiǎn)單的使用加密來(lái)保證基于 cookie 的 token 的安全,另一種是通過(guò)數(shù)據(jù)庫(kù)或其它持久化存儲(chǔ)機(jī)制來(lái)保存生成的 token。這篇文章主要給大家介紹了關(guān)于spring security 5.x實(shí)現(xiàn)兼容多種密碼的加密方式,需要的朋友可以參考下。
    2018-01-01
  • Java中比較器Comparator和Comparable的區(qū)別

    Java中比較器Comparator和Comparable的區(qū)別

    這篇文章主要介紹了Java中比較器Comparator和Comparable的區(qū)別,我們?cè)谑褂?Collections.sort()對(duì)鏈表進(jìn)行排序時(shí),常常需要根據(jù)不同情況自定義排序規(guī)則,今天我們來(lái)看看比較器之間的區(qū)別,需要的朋友可以參考下
    2023-08-08
  • Java中Jackson的多態(tài)反序列化詳解

    Java中Jackson的多態(tài)反序列化詳解

    這篇文章主要介紹了Java中Jackson的多態(tài)反序列化詳解,多態(tài)序列化與反序列化,主要是借助于Jackson的@JsonTypeInfo與@JsonSubTypes注解實(shí)現(xiàn),下面將通過(guò)幾個(gè)例子來(lái)簡(jiǎn)述其運(yùn)用,需要的朋友可以參考下
    2023-11-11
  • Springboot文件上傳功能簡(jiǎn)單測(cè)試

    Springboot文件上傳功能簡(jiǎn)單測(cè)試

    這篇文章主要介紹了Springboot文件上傳功能簡(jiǎn)單測(cè)試,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Jmeter測(cè)試時(shí)遇到的各種亂碼問(wèn)題及解決

    Jmeter測(cè)試時(shí)遇到的各種亂碼問(wèn)題及解決

    這篇文章主要介紹了Jmeter測(cè)試時(shí)遇到的各種亂碼問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Maven配置多倉(cāng)庫(kù)無(wú)效的解決

    Maven配置多倉(cāng)庫(kù)無(wú)效的解決

    在項(xiàng)目中使用Maven管理jar包依賴往往會(huì)出現(xiàn)很多問(wèn)題,所以這時(shí)候就需要配置Maven多倉(cāng)庫(kù),本文介紹了如何配置以及問(wèn)題的解決
    2021-05-05
  • 深入淺析SpringBoot自動(dòng)配置原理

    深入淺析SpringBoot自動(dòng)配置原理

    本文給大家介紹SpringBoot自動(dòng)配置原理解析,springboot使用的是2.3.1版本源碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-10-10
  • Java算法設(shè)計(jì)與分析分治算法

    Java算法設(shè)計(jì)與分析分治算法

    這篇文章主要介紹了Java算法設(shè)計(jì)與分析分治算法,一般分治算法在正文中分解為兩個(gè)即以上的遞歸調(diào)用,并且子類(lèi)問(wèn)題一般是不想交的
    2022-07-07
  • SpringBoot中的MongoTemplate的各種條件查詢示例詳解

    SpringBoot中的MongoTemplate的各種條件查詢示例詳解

    這篇文章主要介紹了SpringBoot中的MongoTemplate的各種條件查詢示例詳解,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借價(jià)值,需要的朋友參考下吧
    2024-01-01
  • 關(guān)于RabbitMQ的Channel默認(rèn)線程

    關(guān)于RabbitMQ的Channel默認(rèn)線程

    這篇文章主要介紹了關(guān)于RabbitMQ的Channel默認(rèn)線程,通過(guò)jvm工具觀察rabbitmq的線程使用情況,發(fā)現(xiàn)生產(chǎn)者每發(fā)一條消息,消費(fèi)者這邊就會(huì)創(chuàng)建一條線程,言下之意,一個(gè)channel當(dāng)消息來(lái)到時(shí)就會(huì)異步處理這些消息,需要的朋友可以參考下
    2023-09-09

最新評(píng)論