Spring Cloud Alibaba之負(fù)載均衡組件 - Ribbon詳解(三)

Ribbon是Netflix公司開(kāi)源的一個(gè)負(fù)載均衡的項(xiàng)目(https://github.com/Netflix/ribbon),它是一個(gè)基于HTTP、TCP的客戶(hù)端負(fù)載均衡器。

服務(wù)端負(fù)載均衡

負(fù)載均衡是微服務(wù)架構(gòu)中必須使用的技術(shù)羊壹,通過(guò)負(fù)載均衡來(lái)實(shí)現(xiàn)系統(tǒng)的高可用核无、集群擴(kuò)容等功能。負(fù)載均衡可通過(guò)硬件設(shè)備及軟件來(lái)實(shí)現(xiàn)汞舱,硬件比如:F5、Array等宗雇,軟件比如:LVS昂芜、Nginx等。


用戶(hù)請(qǐng)求先到達(dá)負(fù)載均衡器(也相當(dāng)于一個(gè)服務(wù))赔蒲,負(fù)載均衡器根據(jù)負(fù)載均衡算法將請(qǐng)求轉(zhuǎn)發(fā)到微服務(wù)泌神。負(fù)載均衡算法有:輪訓(xùn)、隨機(jī)舞虱、加權(quán)輪訓(xùn)欢际、加權(quán)隨機(jī)、地址哈希等方法矾兜,負(fù)載均衡器維護(hù)一份服務(wù)列表损趋,根據(jù)負(fù)載均衡算法將請(qǐng)求轉(zhuǎn)發(fā)到相應(yīng)的微服務(wù)上,所以負(fù)載均衡可以為微服務(wù)集群分擔(dān)請(qǐng)求椅寺,降低系統(tǒng)的壓力

客戶(hù)端負(fù)載均衡

上圖是服務(wù)端負(fù)載均衡舶沿,客戶(hù)端負(fù)載均衡與服務(wù)端負(fù)載均衡的區(qū)別在于客戶(hù)端要維護(hù)一份服務(wù)列表,Ribbon從Eureka Server獲取服務(wù)列表配并,Ribbon根據(jù)負(fù)載均衡算法直接請(qǐng)求到具體的微服務(wù)括荡,中間省去了負(fù)載均衡服務(wù)。

Ribbon負(fù)載均衡的流程圖:


  • 在消費(fèi)微服務(wù)中使用Ribbon實(shí)現(xiàn)負(fù)載均衡溉旋,Ribbon先從Eureka Server 或 Nacos Server中獲取服務(wù)列表畸冲。

  • Ribbon根據(jù)負(fù)載均衡的算法去調(diào)用微服務(wù)。

Ribbon測(cè)試

Spring Cloud引入Ribbon配合 restTemplate 實(shí)現(xiàn)客戶(hù)端負(fù)載均衡。Java中遠(yuǎn)程調(diào)用的技術(shù)有很多邑闲,如:webservice算行、socket、rmi苫耸、Apache HttpClient州邢、OkHttp等。

  1. 在客戶(hù)端添加Ribbon依賴(lài)

注意:由于我們之前整合Nacos時(shí)引入了spring-cloud-starter-alibaba-nacos-discovery這個(gè)依賴(lài)包褪子,而這個(gè)包默認(rèn)已經(jīng)幫我們繼承了Ribbon量淌,所有這里可以不用單獨(dú)引入Ribbon依賴(lài)包。

  1. 配置Ribbon參數(shù)
ribbon:
  MaxAutoRetries: 2  #最大重試次數(shù)嫌褪,當(dāng)Eureka中可以找到服務(wù)呀枢,但是服務(wù)連不上時(shí)將會(huì)重試
  MaxAutoRetriesNextServer: 3  #切換實(shí)例的重試次數(shù)
  OkToRetryOnAllOperations: false  #對(duì)所有操作請(qǐng)求都進(jìn)行重試,如果是get則可以笼痛,如果是post裙秋,put等操作沒(méi)有實(shí)現(xiàn)冪等的情況下是很危險(xiǎn)的,所以設(shè)置為false
  ConnectTimeout: 5000 #請(qǐng)求連接的超時(shí)時(shí)間
  ReadTimeout: 6000  #請(qǐng)求處理的超時(shí)時(shí)間
  1. 負(fù)載均衡測(cè)試

啟動(dòng)兩個(gè)服務(wù),端口需要不一致

定義RestTemplate缨伊,使用@LoadBalanced注解

    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

測(cè)試代碼

@Slf4j
@RestController
public class TestController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/test")
    public String test() {
        String result = restTemplate.getForObject("http://alibaba-nacos-discovery-server/hello?name=wolf", String.class);
        return "Return : " + result;
    }
}

可以看到摘刑,在定義RestTemplate時(shí)候,增加了@LoadBalanced注解刻坊,而在真正調(diào)用服務(wù)接口的時(shí)候枷恕,原來(lái)host部分是通過(guò)手工拼接ip和端口形式。而這里直接采用服務(wù)名來(lái)寫(xiě)請(qǐng)求路徑即可紧唱。在真正調(diào)用的時(shí)候活尊,Spring Cloud會(huì)將請(qǐng)求攔截下來(lái)隶校,然后通過(guò)Ribbon從Nacos Server獲取服務(wù)列表漏益,并通過(guò)負(fù)載均衡器選出節(jié)點(diǎn),并替換服務(wù)名部分為具體的ip和端口深胳,交給RestTemplate去請(qǐng)求绰疤,從而實(shí)現(xiàn)基于服務(wù)名的負(fù)載均衡調(diào)用。

Ribbon饑餓加載

默認(rèn)情況下Ribbon是懶加載的舞终。當(dāng)服務(wù)起動(dòng)好之后轻庆,第一次請(qǐng)求是非常慢的,第二次之后就快很多敛劝。

解決方式:開(kāi)啟饑餓加載

ribbon:
 eager-load:
  enabled: true #開(kāi)啟饑餓加載
  clients: server-1,server-2,server-3 #為哪些服務(wù)的名稱(chēng)開(kāi)啟饑餓加載,多個(gè)用逗號(hào)分隔

Ribbon組件

接口 作用 默認(rèn)值
IclientConfig 讀取配置 DefaultClientConfigImpl
IRule 負(fù)載均衡規(guī)則余爆,選擇實(shí)例 ZoneAvoidanceRule
IPing 篩選掉ping不通的實(shí)例 DummyPing(該類(lèi)什么不干,認(rèn)為每個(gè)實(shí)例都可用夸盟,都能ping通)
ServerList<Server> 交給Ribbon的實(shí)例列表 Ribbon:ConfigurationBasedServerList
Spring Cloud Alibaba:NacosServerList
ServerListFilter<Server> 過(guò)濾掉不符合條件的實(shí)例 ZonePreferenceServerListFilter
ILoadBalancer Ribbon的入口 ZoneAwareLoadBalancer
ServerListUpdater 更新交給Ribbon的List的策略 PollingServerListUpdater

這里的每一項(xiàng)都可以自定義:
IclientConfig Ribbon支持非常靈活的配置就是有該組件提供的
IRule 為Ribbon提供規(guī)則蛾方,從而選擇實(shí)例、該組件是最核心組件

舉例:

  • 代碼方式:
@Configuration
public class RibbonRuleConfig {
    @Bean
    public IRule ribbonRulr() {
        return new RandomRule();
    }
    @Bean
    public IPing iPing(){
        return new PingUrl();
    }
}
  • 配置屬性方式:
<clientName>:
 ribbon:
  NFLoadBalancerClassName: #ILoadBalancer該接口實(shí)現(xiàn)類(lèi)
  NFLoadBalancerRuleClassName: #IRule該接口實(shí)現(xiàn)類(lèi)
  NFLoadBalancerPingClassName: #Iping該接口實(shí)現(xiàn)類(lèi)
  NIWSServerListClassName: #ServerList該接口實(shí)現(xiàn)類(lèi)
  NIWSServerListFilterClassName: #ServiceListFilter該接口實(shí)現(xiàn)類(lèi)

在這些屬性中定義的類(lèi)優(yōu)先于使用@RibbonClient(configuration=RibbonConfig.class)Spring 定義的bean 以及由Spring Cloud Netflix提供的默認(rèn)值。描述:配置文件中定義ribbon優(yōu)先代碼定義

Ribbon負(fù)載均衡的八種算法桩砰,其中ResponseTimeWeightedRule已廢除

規(guī)則名稱(chēng) 特點(diǎn)
AvailabilityFilteringRule 過(guò)濾掉一直連接失敗的被標(biāo)記為circuit tripped(電路跳閘)的后端Service拓春,并過(guò)濾掉那些高并發(fā)的后端Server或者使用一個(gè)AvailabilityPredicate來(lái)包含過(guò)濾Server的邏輯,其實(shí)就是檢查status的記錄的各個(gè)Server的運(yùn)行狀態(tài)
BestAvailableRule 選擇一個(gè)最小的并發(fā)請(qǐng)求的Server亚隅,逐個(gè)考察Server硼莽,如果Server被tripped了,則跳過(guò)
RandomRule 隨機(jī)選擇一個(gè)Server
ResponseTimeWeightedRule 已廢棄煮纵,作用同WeightedResponseTimeRule
RetryRule 對(duì)選定的負(fù)責(zé)均衡策略機(jī)上充值機(jī)制懂鸵,在一個(gè)配置時(shí)間段內(nèi)當(dāng)選擇Server不成功,則一直嘗試使用subRule的方式選擇一個(gè)可用的Server
RoundRobinRule 輪詢(xún)選擇醉途,輪詢(xún)index矾瑰,選擇index對(duì)應(yīng)位置Server
WeightedResponseTimeRule 根據(jù)相應(yīng)時(shí)間加權(quán),相應(yīng)時(shí)間越長(zhǎng)隘擎,權(quán)重越小殴穴,被選中的可能性越低
ZoneAvoidanceRule (默認(rèn)是這個(gè))負(fù)責(zé)判斷Server所Zone的性能和Server的可用性選擇Server,在沒(méi)有Zone的環(huán)境下货葬,類(lèi)似于輪詢(xún)(RoundRobinRule)

實(shí)現(xiàn)負(fù)載均衡<細(xì)粒度>配置-隨機(jī)

  • 方式一:代碼方式
    首先定義RestTemplate采幌,并且添加注解@LoadBalanced,這樣RestTemplate就實(shí)現(xiàn)了負(fù)載均衡
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
//template.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));//解決中文亂碼
return new RestTemplate();
}

在SpringBootApplication主類(lèi)下添加配置類(lèi)震桶。該類(lèi)主要作用于為哪個(gè)服務(wù)做負(fù)載均衡休傍。默認(rèn)的是輪訓(xùn)

@Configuration
@RibbonClient(name = "${服務(wù)名稱(chēng)}", configuration = GoodsRibbonRuleConfig.class)//configuration: 指向負(fù)載均衡規(guī)則的配置類(lèi)
public class GoodsRibbonConfig {
}

添加Ribbon的配置類(lèi),注意該類(lèi)必須配置在@SpringBootApplication主類(lèi)以外的包下蹲姐。不然的話(huà)所有的服務(wù)都會(huì)按照這個(gè)規(guī)則來(lái)實(shí)現(xiàn)磨取。會(huì)被所有的RibbonClient共享。主要是主類(lèi)的主上下文和Ribbon的子上下文起沖突了柴墩。父子上下文不能重疊

@Configuration
public class GoodsRibbonRuleConfig {
    @Bean
    public IRule ribbonRulr() {
        return new RandomRule();
    }
}
  • 方式二:配置屬性方式
server-1: # 服務(wù)名稱(chēng) Service-ID
  ribbon:
    # 屬性配置方式【推薦】
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #  配置文件配置負(fù)載均衡算法-我這里使用的是自定義的Ribbon的負(fù)載均衡算法忙厌,默認(rèn)

優(yōu)先級(jí):配置(不會(huì)影響其他服務(wù))>(大于) 硬編碼(類(lèi)得寫(xiě)在SpringBoot啟動(dòng)類(lèi)包外,不然會(huì)影響其他服務(wù))

總結(jié):

配置方式 優(yōu)點(diǎn) 缺點(diǎn)
代碼配置 基于代碼江咳,更加靈活 有坑(父子上下文)
線(xiàn)上修改得重新打包逢净,發(fā)布
屬性配置 易上手 配置更加直觀
線(xiàn)上修改無(wú)需重新打包,發(fā)布
優(yōu)先級(jí)更高
極端場(chǎng)景下沒(méi)有配置配置方式靈活

實(shí)現(xiàn)負(fù)載均衡<全局>配置-隨機(jī)

  • 方式一:Ribbon的配置類(lèi)定義在主類(lèi)下
    讓ComponentScan上下文重疊(強(qiáng)烈不建議使用)
  • 方式二:
@Configuration
@RibbonClients(defaultConfiguration = GoodsRibbonRuleConfig.class)//Ribbon負(fù)載均衡全局粒度配置(所有服務(wù)都按照這個(gè)配置)
public class RibbonConfig {
}

擴(kuò)展Ribbon-支持Nacos權(quán)重

默認(rèn)情況下Ribbon是不支持Nacos的權(quán)重負(fù)載均衡選擇的歼指,這里我們自己擴(kuò)展一個(gè)Rule爹土,然Ribbon支持Nacos的權(quán)重規(guī)則。

  1. 創(chuàng)建NacosWeightedRule類(lèi)
package com.thtf.contentcenter.configuration;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;


@Slf4j
public class NacosWeightedRule extends AbstractLoadBalancerRule {
    
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;
    
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
        //讀取配置文件踩身,并初始化
    }

    @Override
    public Server choose(Object o) {
        try {
            BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
            //想要請(qǐng)求的微服務(wù)名稱(chēng)
            String name = loadBalancer.getName();
            //實(shí)現(xiàn)負(fù)載均衡算法
            //拿到服務(wù)發(fā)現(xiàn)相關(guān)API
            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
            //nacos client自動(dòng)通過(guò)基于權(quán)重的負(fù)載均衡算法胀茵,給我們選擇一個(gè)實(shí)例。
            Instance instance = namingService.selectOneHealthyInstance(name);
            
            log.info("選擇的實(shí)例是:port = {}, instance = {}", instance.getPort(), instance);
            return new NacosServer(instance);
        } catch (NacosException e) {
            log.error("選擇實(shí)例異常:{}", e.getMessage(), e);
            return null;
        }
    }
}
  1. 創(chuàng)建RibbonConfiguration類(lèi)
package com.thtf.contentcenter.ribbonconfiguration;

import com.istimeless.contentcenter.configuration.NacosWeightedRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RibbonConfiguration {
    
    @Bean
    public IRule ribbonRule() {
        return new NacosWeightedRule();
    }
}

特別注意:RibbonConfiguration要建在啟動(dòng)類(lèi)掃描不到的地方挟阻,如圖所示:

  1. 創(chuàng)建UserCenterRibbonConfiguration類(lèi)琼娘,實(shí)現(xiàn)全局配置
package com.thtf.contentcenter.configuration;

import com.istimeless.ribbonconfiguration.RibbonConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;

@Configuration
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
}

擴(kuò)展Ribbon-同集群優(yōu)先

在Nacos上呵哨,支持集群配置。集群是指對(duì)指定微服務(wù)的一種虛擬分類(lèi)轨奄。集群還是比較有用的孟害,例如:

  • 為了容災(zāi),把指定微服務(wù)同時(shí)部署在兩個(gè)機(jī)房(例如同城多活挪拟,其中1個(gè)機(jī)房崩潰了挨务,另一個(gè)機(jī)房還能頂上,異地多活防止自然災(zāi)害)
  • 調(diào)用時(shí)玉组,可優(yōu)先調(diào)用同機(jī)房的實(shí)例谎柄,如果同機(jī)房沒(méi)有實(shí)例,再跨機(jī)房調(diào)用惯雳。

雖然Spring Cloud Alibaba支持集群配置朝巫,例如:

spring: 
  cloud:    
    nacos:  
      discovery:    
        # 北京機(jī)房集群    
        cluster-name: BJ

但在調(diào)用時(shí),服務(wù)消費(fèi)者并不會(huì)優(yōu)先調(diào)用同集群的實(shí)例石景。
本節(jié)來(lái)探討如何擴(kuò)展Ribbon劈猿,從而實(shí)現(xiàn)同集群優(yōu)先調(diào)用的效果,并且還能支持Nacos權(quán)重配置潮孽。關(guān)于權(quán)重配置揪荣,前面已經(jīng)實(shí)現(xiàn)了,在前面的基礎(chǔ)上實(shí)現(xiàn)同集群優(yōu)先策略往史。

/** 
 * 支持優(yōu)先調(diào)用同集群實(shí)例的ribbon負(fù)載均衡規(guī)則.    
 *  
 * @author itmuch.com   
 */ 
@Slf4j  
public class NacosRule extends AbstractLoadBalancerRule {   
    @Autowired  
    private NacosDiscoveryProperties nacosDiscoveryProperties;  
    
    @Override   
    public Server choose(Object key) {  
        try {   
            String clusterName = this.nacosDiscoveryProperties.getClusterName();    
            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer(); 
            String name = loadBalancer.getName();   
    
            NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();    
        // 1. 找到指定服務(wù)的所有實(shí)例 A
            List<Instance> instances = namingService.selectInstances(name, true);   
            if (CollectionUtils.isEmpty(instances)) {   
                return null;    
            }   
    
            List<Instance> instancesToChoose = instances;   
            if (StringUtils.isNotBlank(clusterName)) {  
                // 2. 過(guò)濾出相同集群下的所有實(shí)例 B
                List<Instance> sameClusterInstances = instances.stream()    
                        .filter(instance -> Objects.equals(clusterName, instance.getClusterName())) 
                        .collect(Collectors.toList());  
                // 3. 如果B為空仗颈,就用A
                if (!CollectionUtils.isEmpty(sameClusterInstances)) {   
                    instancesToChoose = sameClusterInstances;   
                } else {    
                    log.warn("發(fā)生跨集群的調(diào)用,name = {}, clusterName = {}, instance = {}", name, clusterName, instances);  
                }   
            }   
        // 4. 基于權(quán)重的負(fù)載均衡算法椎例,返回一個(gè)實(shí)例
            Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);   
       
            return new NacosServer(instance);   
        } catch (Exception e) { 
            log.warn("NacosRule發(fā)生異常", e);   
            return null;    
        }   
    }   
    
    @Override   
    public void initWithNiwsConfig(IClientConfig iClientConfig) {   
    }   
}

負(fù)載均衡算法:

// Balancer來(lái)自于com.alibaba.nacos.client.naming.core.Balancer挨决,也就是Nacos Client自帶的基于權(quán)重的負(fù)載均衡算法。  
public class ExtendBalancer extends Balancer {  
    /** 
     * 根據(jù)權(quán)重订歪,隨機(jī)選擇實(shí)例  
     *  
     * @param instances 實(shí)例列表    
     * @return 選擇的實(shí)例    
     */ 
    public static Instance getHostByRandomWeight2(List<Instance> instances) {   
        return getHostByRandomWeight(instances);    
    }   
}

配置:

microservice-provider-user: 
  ribbon:   
    NFLoadBalancerRuleClassName: com.itmuch.cloud.study.ribbon.NacosClusterAwareWeightedRule

這樣脖祈,服務(wù)在調(diào)用microservice-provider-user 這個(gè)服務(wù)時(shí),就會(huì)優(yōu)先選擇相同集群下的實(shí)例陌粹。

擴(kuò)展Ribbon-基于元數(shù)據(jù)的版本控制

至此撒犀,已經(jīng)實(shí)現(xiàn)了

  • 優(yōu)先調(diào)用同集群下的實(shí)例
  • 實(shí)現(xiàn)基于權(quán)重配置的負(fù)載均衡
    但實(shí)際項(xiàng)目福压,我們可能還會(huì)有這樣的需求:
    一個(gè)微服務(wù)在線(xiàn)上可能多版本共存掏秩,例如:
  • 服務(wù)提供者有兩個(gè)版本:v1、v2
  • 服務(wù)消費(fèi)者也有兩個(gè)版本:v1荆姆、v2
    v1/v2是不兼容的蒙幻。服務(wù)消費(fèi)者v1只能調(diào)用服務(wù)提供者v1;消費(fèi)者v2只能調(diào)用提供者v2胆筒。如何實(shí)現(xiàn)呢邮破?

下面圍繞該場(chǎng)景诈豌,實(shí)現(xiàn)微服務(wù)之間的版本控制。

元數(shù)據(jù)
元數(shù)據(jù)就是一堆的描述信息抒和,以map存儲(chǔ)矫渔。舉個(gè)例子:

spring:
  cloud:
    nacos:
        metadata: 
          # 自己這個(gè)實(shí)例的版本
          version: v1
          # 允許調(diào)用的提供者版本
          target-version: v1

需求分析

我們需要實(shí)現(xiàn)的有兩點(diǎn):

  • 優(yōu)先選擇同集群下,符合metadata的實(shí)例
  • 如果同集群加沒(méi)有符合metadata的實(shí)例摧莽,就選擇所有集群下庙洼,符合metadata的實(shí)例

代碼實(shí)現(xiàn)

@Slf4j
public class NacosFinalRule extends AbstractLoadBalancerRule {
    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public Server choose(Object key) {
        // 負(fù)載均衡規(guī)則:優(yōu)先選擇同集群下,符合metadata的實(shí)例
        // 如果沒(méi)有镊辕,就選擇所有集群下油够,符合metadata的實(shí)例

        // 1. 查詢(xún)所有實(shí)例 A
        // 2. 篩選元數(shù)據(jù)匹配的實(shí)例 B
        // 3. 篩選出同cluster下元數(shù)據(jù)匹配的實(shí)例 C
        // 4. 如果C為空,就用B
        // 5. 隨機(jī)選擇實(shí)例
        try {
            String clusterName = this.nacosDiscoveryProperties.getClusterName();
            String targetVersion = this.nacosDiscoveryProperties.getMetadata().get("target-version");

            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String name = loadBalancer.getName();

            NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();

            // 所有實(shí)例
            List<Instance> instances = namingService.selectInstances(name, true);

            List<Instance> metadataMatchInstances = instances;
            // 如果配置了版本映射征懈,那么只調(diào)用元數(shù)據(jù)匹配的實(shí)例
            if (StringUtils.isNotBlank(targetVersion)) {
                metadataMatchInstances = instances.stream()
                        .filter(instance -> Objects.equals(targetVersion, instance.getMetadata().get("version")))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(metadataMatchInstances)) {
                    log.warn("未找到元數(shù)據(jù)匹配的目標(biāo)實(shí)例石咬!請(qǐng)檢查配置。targetVersion = {}, instance = {}", targetVersion, instances);
                    return null;
                }
            }

            List<Instance> clusterMetadataMatchInstances = metadataMatchInstances;
            // 如果配置了集群名稱(chēng)卖哎,需篩選同集群下元數(shù)據(jù)匹配的實(shí)例
            if (StringUtils.isNotBlank(clusterName)) {
                clusterMetadataMatchInstances = metadataMatchInstances.stream()
                        .filter(instance -> Objects.equals(clusterName, instance.getClusterName()))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(clusterMetadataMatchInstances)) {
                    clusterMetadataMatchInstances = metadataMatchInstances;
                    log.warn("發(fā)生跨集群調(diào)用鬼悠。clusterName = {}, targetVersion = {}, clusterMetadataMatchInstances = {}", clusterName, targetVersion, clusterMetadataMatchInstances);
                }
            }

            Instance instance = ExtendBalancer.getHostByRandomWeight2(clusterMetadataMatchInstances);
            return new NacosServer(instance);
        } catch (Exception e) {
            log.warn("發(fā)生異常", e);
            return null;
        }
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }
}

** 負(fù)載均衡算法:**

public class ExtendBalancer extends Balancer {
    /**
     * 根據(jù)權(quán)重,隨機(jī)選擇實(shí)例
     *
     * @param instances 實(shí)例列表
     * @return 選擇的實(shí)例
     */
    public static Instance getHostByRandomWeight2(List<Instance> instances) {
        return getHostByRandomWeight(instances);
    }
}

思考

截止到這里亏娜,我們已經(jīng)對(duì)Ribbon的基本使用已經(jīng)如何自定義Ribbon負(fù)載均衡規(guī)則做了詳細(xì)說(shuō)明厦章,但細(xì)心的人會(huì)發(fā)現(xiàn),我使用上面 RestTemplate 地址拼接方式調(diào)用服務(wù)接口會(huì)存在以下幾點(diǎn)不足:

  • 代碼可讀性差
  • 復(fù)雜的url接口地址難以維護(hù)
  • 編碼體驗(yàn)不統(tǒng)一

帶著這些不足照藻,我們引入下一章要講解的另一種服務(wù)調(diào)用方式:Feign

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末袜啃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子幸缕,更是在濱河造成了極大的恐慌群发,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件发乔,死亡現(xiàn)場(chǎng)離奇詭異熟妓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)栏尚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)起愈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人译仗,你說(shuō)我怎么就攤上這事抬虽。” “怎么了纵菌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵阐污,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我咱圆,道長(zhǎng)笛辟,這世上最難降的妖魔是什么功氨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮手幢,結(jié)果婚禮上捷凄,老公的妹妹穿的比我還像新娘。我一直安慰自己围来,他們只是感情好纵势,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著管钳,像睡著了一般钦铁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上才漆,一...
    開(kāi)封第一講書(shū)人閱讀 50,021評(píng)論 1 291
  • 那天牛曹,我揣著相機(jī)與錄音,去河邊找鬼醇滥。 笑死黎比,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鸳玩。 我是一名探鬼主播阅虫,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼不跟!你這毒婦竟也來(lái)了颓帝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窝革,失蹤者是張志新(化名)和其女友劉穎购城,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體虐译,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瘪板,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了漆诽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侮攀。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖厢拭,靈堂內(nèi)的尸體忽然破棺而出兰英,到底是詐尸還是另有隱情,我是刑警寧澤蚪腐,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布箭昵,位于F島的核電站税朴,受9級(jí)特大地震影響回季,放射性物質(zhì)發(fā)生泄漏家制。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一泡一、第九天 我趴在偏房一處隱蔽的房頂上張望颤殴。 院中可真熱鬧,春花似錦鼻忠、人聲如沸涵但。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)矮瘟。三九已至,卻和暖如春塑娇,著一層夾襖步出監(jiān)牢的瞬間澈侠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工埋酬, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哨啃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓写妥,卻偏偏與公主長(zhǎng)得像拳球,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子珍特,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容