ribbon 是一個客戶端負(fù)載均衡器,可以簡單的理解成類似于 nginx的負(fù)載均衡模塊的功能。
Load Balance負(fù)載均衡是用于解決一臺機(jī)器(一個進(jìn)程)無法解決所有請求而產(chǎn)生的一種算法。像nginx可以使用負(fù)載均衡分配流量,ribbon為客戶端提供負(fù)載均衡,dubbo服務(wù)調(diào)用里的負(fù)載均衡等等,很多地方都使用到了負(fù)載均衡。
主流的Load Balance方案可分成兩類:
一種是集中式Load Balance, 即在服務(wù)的消費(fèi)方和提供方之間使用獨(dú)立的LB設(shè)施(可以是硬件,如F5, 也可以是軟件,如nginx), 由該設(shè)施負(fù)責(zé)把訪問請求通過某種策略轉(zhuǎn)發(fā)至服務(wù)的提供方;
另一種是進(jìn)程內(nèi)Load Balance,將LB邏輯集成到消費(fèi)方,消費(fèi)方從服務(wù)注冊中心獲知有哪些地址可用,然后自己再從這些地址中選擇出一個合適的服務(wù)器。Ribbon就屬于后者,它只是一個類庫,集成于消費(fèi)方進(jìn)程,消費(fèi)方通過它來獲取到服務(wù)提供方的地址。
使用負(fù)載均衡帶來的好處很明顯:
當(dāng)集群里的1臺或者多臺服務(wù)器down的時候,剩余的沒有down的服務(wù)器可以保證服務(wù)的繼續(xù)使用
使用了更多的機(jī)器保證了機(jī)器的良性使用,不會由于某一高峰時刻導(dǎo)致系統(tǒng)cpu急劇上升
負(fù)載均衡有好幾種實(shí)現(xiàn)策略,常見的有:
- 隨機(jī) (Random)
- 輪詢 (RoundRobin)
- 一致性哈希 (ConsistentHash)
- 哈希 (Hash)
- 加權(quán)(Weighted)
Ribbon的組成:
| 接口 | 作用 | 默認(rèn)值 |
|---|---|---|
| IClientConfig | 讀取配置 | DefaultClientConfigImpl |
| IRule | 負(fù)載均衡規(guī)則,選擇實(shí)例 | ZoneAvoidanceRule |
| IPing | 篩選掉ping不通的實(shí)例 | DummyPing |
| ServerList<Server> | 交給Ribbon的實(shí)例列表 | Ribbon:ConfigurationBasedServerList Spring Cloud Alibaba:NacosServerList |
| ServerListFilter<Server> | 過濾掉不符合條件的實(shí)例 | ZonePreferenceServerListFilter |
| ILoadBalance | Ribbon的入口 | ZoneAwareLoadBalance |
| ServerListUpdater | 更新交給Ribbon的List的策略 | PollingServerListUpdater |
Ribbon是比較靈活的,它對所有的組件都定義成了接口,如果對默認(rèn)值不滿意,可以實(shí)現(xiàn)這些接口配置一下,就可以將默認(rèn)實(shí)現(xiàn)替換掉。
ILoadBalance 負(fù)載均衡器
ribbon是一個為客戶端提供負(fù)載均衡功能的服務(wù),它內(nèi)部提供了一個叫做ILoadBalance的接口代表負(fù)載均衡器的操作,比如有添加服務(wù)器操作、選擇服務(wù)器操作、獲取所有的服務(wù)器列表、獲取可用的服務(wù)器列表等等。
ILoadBalance的實(shí)現(xiàn)類如下:

負(fù)載均衡器是從服務(wù)發(fā)現(xiàn)組件(NacosDiscoveryClient或EurekaClient)(DiscoveryClient的實(shí)現(xiàn)類為NacosDiscoveryClient)獲取服務(wù)信息,根據(jù)IRule去路由,并且根據(jù)IPing判斷服務(wù)的可用性。
負(fù)載均衡器多久一次去獲取一次從DiscoveryClient獲取注冊信息呢?在BaseLoadBalancer類下,BaseLoadBalancer的構(gòu)造函數(shù),該構(gòu)造函數(shù)開啟了一個PingTask任務(wù)setupPingTask();,代碼如下:
public BaseLoadBalancer(String name, IRule rule, LoadBalancerStats stats, IPing ping, IPingStrategy pingStrategy) {
this.rule = DEFAULT_RULE;
this.pingStrategy = DEFAULT_PING_STRATEGY;
this.ping = null;
this.allServerList = Collections.synchronizedList(new ArrayList());
this.upServerList = Collections.synchronizedList(new ArrayList());
this.allServerLock = new ReentrantReadWriteLock();
this.upServerLock = new ReentrantReadWriteLock();
this.name = "default";
this.lbTimer = null;
this.pingIntervalSeconds = 10;
this.maxTotalPingTimeSeconds = 5;
this.serverComparator = new ServerComparator();
this.pingInProgress = new AtomicBoolean(false);
this.counter = Monitors.newCounter("LoadBalancer_ChooseServer");
this.enablePrimingConnections = false;
this.changeListeners = new CopyOnWriteArrayList();
this.serverStatusListeners = new CopyOnWriteArrayList();
logger.debug("LoadBalancer [{}]: initialized", name);
this.name = name;
this.ping = ping;
this.pingStrategy = pingStrategy;
this.setRule(rule);
this.setupPingTask();
this.lbStats = stats;
this.init();
}
setupPingTask()的具體代碼邏輯,它開啟了ShutdownEnabledTimer執(zhí)行PingTask任務(wù),在默認(rèn)情況下pingIntervalSeconds為10,即每10秒鐘,向EurekaClient發(fā)送一次”ping”。
void setupPingTask() {
if (!this.canSkipPing()) {
if (this.lbTimer != null) {
this.lbTimer.cancel();
}
this.lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + this.name, true);
this.lbTimer.schedule(new BaseLoadBalancer.PingTask(), 0L, (long)(this.pingIntervalSeconds * 1000));
this.forceQuickPing();
}
}
PingTask源碼,即new一個Pinger對象,并執(zhí)行runPinger()方法。
查看Pinger的runPinger()方法,最終根據(jù) pingerStrategy.pingServers(ping, allServers)來獲取服務(wù)的可用性,如果該返回結(jié)果,如之前相同,則不去向EurekaClient獲取注冊列表,如果不同則通知ServerStatusChangeListener或者changeListeners發(fā)生了改變,進(jìn)行更新或者重新拉取。
完整過程是:
LoadBalancerClient(RibbonLoadBalancerClient是實(shí)現(xiàn)類)在初始化的時候(execute方法),會通過ILoadBalance(BaseLoadBalancer是實(shí)現(xiàn)類)向Eureka注冊中心獲取服務(wù)注冊列表,并且每10s一次向EurekaClient或NacosClient發(fā)送“ping”,來判斷服務(wù)的可用性,如果服務(wù)的可用性發(fā)生了改變或者服務(wù)數(shù)量和之前的不一致,則從注冊中心更新或者重新拉取。LoadBalancerClient有了這些服務(wù)注冊列表,就可以根據(jù)具體的IRule來進(jìn)行負(fù)載均衡。
IRule 路由
IRule接口代表負(fù)載均衡策略:
public interface IRule {
Server choose(Object var1);
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();
}
IRule接口的實(shí)現(xiàn)類有以下幾種:

Ribbon內(nèi)置的負(fù)載均衡規(guī)則:
| 規(guī)則名稱 | 特點(diǎn) |
|---|---|
| AvailabilityFilteringRule | 過濾掉一直連接失敗的被標(biāo)記為circuit tripped的后端Server,并 過濾掉那些高并發(fā)的后端Server或者使用一個AvailabilityPredicate 來包含過濾server的邏輯,其實(shí)就是檢查status里記錄的各個server 的運(yùn)行狀態(tài) |
| BestAvailableRule | 選擇一個最小的并發(fā)請求的server,逐個考察server, 如果Server被tripped了,則跳過 |
| RandomRule | 隨機(jī)選擇一個Server |
| ResponseTimeWeightedRule | 已廢棄,作用同WeightedResponseTimeRule |
| WeightedResponseTimeRule | 根據(jù)響應(yīng)時間加權(quán),響應(yīng)時間越長,權(quán)重越小,被選中的可能性越低 |
| RetryRule | 對選定的負(fù)載均衡策略加上重試機(jī)制,在一個配置時間段內(nèi)當(dāng) 選擇Server不成功,則一直嘗試使用subRule的方式選擇一個 可用的Server |
| RoundRobinRule | 輪詢選擇,輪詢index,選擇index對應(yīng)位置的Server |
| ZoneAvoidanceRule | 默認(rèn)的負(fù)載均衡策略,即復(fù)合判斷Server所在區(qū)域的性能和Server的可用性 選擇Server,在沒有區(qū)域的環(huán)境下,類似于輪詢(RandomRule) |
其中RandomRule表示隨機(jī)策略、RoundRobinRule表示輪詢策略、WeightedResponseTimeRule表示加權(quán)策略、BestAvailableRule表示請求數(shù)最少策略等等。
隨機(jī)策略很簡單,就是從服務(wù)器中隨機(jī)選擇一個服務(wù)器,RandomRule的實(shí)現(xiàn)代碼如下:
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
Server server = null;
while(server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
int index = this.chooseRandomInt(serverCount) ;//隨機(jī)獲取索引值index
server = (Server)upList.get(index); // 得到服務(wù)器實(shí)例
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
RoundRobinRule輪詢策略表示每次都取下一個服務(wù)器,比如一共有5臺服務(wù)器,第1次取第1臺,第2次取第2臺,第3次取第3臺,以此類推:
WeightedResponseTimeRule繼承了RoundRobinRule,開始的時候還沒有權(quán)重列表,采用父類的輪詢方式,有一個默認(rèn)每30秒更新一次權(quán)重列表的定時任務(wù),該定時任務(wù)會根據(jù)實(shí)例的響應(yīng)時間來更新權(quán)重列表,choose方法做的事情就是,用一個(0,1)的隨機(jī)double數(shù)乘以最大的權(quán)重得到randomWeight,然后遍歷權(quán)重列表,找出第一個比randomWeight大的實(shí)例下標(biāo),然后返回該實(shí)例,代碼略。
BestAvailableRule策略用來選取最少并發(fā)量請求的服務(wù)器:
public Server choose(Object key) {
if (loadBalancerStats == null) {
return super.choose(key);
}
List<Server> serverList = getLoadBalancer().getAllServers();
int minimalConcurrentConnections = Integer.MAX_VALUE;
long currentTime = System.currentTimeMillis();
Server chosen = null;
for (Server server: serverList) {
ServerStats serverStats = loadBalancerStats.getSingleServerStat(server);
if (!serverStats.isCircuitBreakerTripped(currentTime)) {
int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
if (concurrentConnections < minimalConcurrentConnections) {
minimalConcurrentConnections = concurrentConnections;
chosen = server;
}
}
}
if (chosen == null) {
return super.choose(key);
} else {
return chosen;
}
}
使用Ribbon提供的負(fù)載均衡策略很簡單,只需以下幾部:
1、創(chuàng)建具有負(fù)載均衡功能的RestTemplate實(shí)例
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
使用RestTemplate進(jìn)行rest操作的時候,會自動使用負(fù)載均衡策略,它內(nèi)部會在RestTemplate中加入LoadBalancerInterceptor這個攔截器,這個攔截器的作用就是使用負(fù)載均衡。
默認(rèn)情況下會采用輪詢策略,如果希望采用其它策略,則指定IRule實(shí)現(xiàn),如:
@Bean
public IRule ribbonRule() {
return new BestAvailableRule();
}
這種方式對Feign也有效。
2、實(shí)現(xiàn)Ribbon細(xì)粒度的配置,即如果微服務(wù)order-center調(diào)用微服務(wù)user-center和微服務(wù)goods-center,order-center調(diào)用user-center使用隨機(jī),order-center調(diào)用goods-center使用默認(rèn)ZoneAvoidanceRule
- Java代碼配置
@Configuration
@RibbonClient(name="user-center",configuration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
}
在SpringBoot啟動類以外新建ribbonconfiguration包,并新建RibbonConfiguration類
/**
* @author: huangyibo
* @Date: 2019/11/2 18:08
* @Description: 如果將此類放進(jìn)啟動類的包下,那么此工程的所有ribbon都會使用這種負(fù)載均衡規(guī)則
*/
@Configuration
public class RibbonConfiguration {
//Ribbon提供的負(fù)載均衡策略
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}
- 用配置屬性配置
# 通過配置文件指定user-center實(shí)例的ribbon負(fù)載均衡策略為RandomRule,和java代碼方式指定效果一樣
user-center:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
-
Ribbon細(xì)粒度配置最佳實(shí)踐總結(jié)
代碼配置方式 VS 屬性配置方式
image.png
1)、盡量使用屬性配置,屬性方式實(shí)現(xiàn)不了的情況下再考慮使用代碼配置
2)、在同一個微服務(wù)內(nèi)盡量保持單一性,比如統(tǒng)一使用屬性配置,不要兩種方式混用,增加代碼定位的復(fù)雜性
3、實(shí)現(xiàn)Ribbon的全局配置
@Configuration
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)//Ribbon負(fù)載均衡的全局配置
public class UserCenterRibbonConfiguration {
}
4、前面表格中的Ribbon的組成每一項(xiàng)都可以自定義,例如:
- Java代碼配置
@Configuration
public class RibbonConfiguration {
//Ribbon提供的負(fù)載均衡策略
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
@Bean
public IPing ping(){
return new PingUrl();
}
}
- 用配置屬性配置
clientName.ribbon.如下屬性: - NFLoadBalancerClassName:ILoadBalancer實(shí)現(xiàn)類
- NFLoadBalancerRuleClassName:IRule實(shí)現(xiàn)類
- NFLoadBalancerPingClassName:IPing實(shí)現(xiàn)類
- NIWSServerListClassName:ServerList實(shí)現(xiàn)類
- NIWSServerListFilterClassName:ServerListFilter實(shí)現(xiàn)類
5、Ribbon的饑餓加載,Ribbon默認(rèn)是懶加載的
ribbon:
eager-load:
# 開啟ribbon饑餓加載
enabled: true
# 配置user-center使用ribbon饑餓加載,多個使用逗號分隔
clients: user-center
6、擴(kuò)展Ribbon,支持Nocas權(quán)重
-
編輯Nacos權(quán)重
image.png
新建NacosWeightedRule
/**
* @author: huangyibo
* @Date: 2019/11/2 18:44
* @Description: 繼承AbstractLoadBalancerRule編寫負(fù)載均衡算法,支持Nacos的權(quán)重
*/
@Slf4j
public class NacosWeightedRule extends AbstractLoadBalancerRule {
/**
* NacosDiscoveryProperties內(nèi)置了基于權(quán)重的負(fù)載均衡算法
*/
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
/**
* 讀取配置文件并初始化NacosWeightedRule
* @param iClientConfig
*/
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
/**
* 實(shí)現(xiàn)基于權(quán)重的負(fù)載均衡算法
* @param o
*/
@Override
public Server choose(Object o) {
try {
BaseLoadBalancer loadBalancer = (BaseLoadBalancer)this.getLoadBalancer();
log.info("loadBalancer={}",loadBalancer);
//想要請求的微服務(wù)名稱
String name = loadBalancer.getName();
//拿到服務(wù)發(fā)現(xiàn)新的相關(guān)的api
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
//Nacos client自動通過基于權(quán)重的負(fù)載均衡算法,給我們選擇一個實(shí)例
Instance instance = namingService.selectOneHealthyInstance(name);
log.info("Nacos client選擇的實(shí)例:port={} , instance={}",instance.getPort(),instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("Nacos client自動通過基于權(quán)重的負(fù)載均衡算法,選擇微服務(wù)實(shí)例異常,e={}",e);
return null;
}
}
}
//spring cloud commons ---> 定義了標(biāo)準(zhǔn)
//spring cloud loadbalancer --->定義了各種負(fù)載均衡器的標(biāo)準(zhǔn) 沒有權(quán)重
配置NacosWeightedRule
@Configuration
public class RibbonConfiguration {
//自定義負(fù)載均衡配置,通過Nacos client自動通過基于權(quán)重的負(fù)載均衡算法,給我們選擇一個實(shí)例
@Bean
public IRule ribbonRule(){
return new NacosWeightedRule();
}
}
@Configuration
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)//Ribbon負(fù)載均衡的全局配置
public class UserCenterRibbonConfiguration {
}
7、擴(kuò)展Ribbon,實(shí)現(xiàn)Nacos注冊中心同一集群優(yōu)先調(diào)用
新建NacosSameClusterWeightedRule
/**
* @author: huangyibo
* @Date: 2019/11/2 19:03
* @Description: 繼承AbstractLoadBalancerRule拓展Ribbon,進(jìn)行同一集群下服務(wù)優(yōu)先調(diào)用,這個是針對的異地災(zāi)備的
*/
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object o) {
try {
//拿到配置文件中的集群名稱 shenzhen
String clusterName = nacosDiscoveryProperties.getClusterName();
BaseLoadBalancer loadBalancer = (BaseLoadBalancer)this.getLoadBalancer();
log.info("loadBalancer={}",loadBalancer);
//想要請求的微服務(wù)名稱
String name = loadBalancer.getName();
//拿到服務(wù)發(fā)現(xiàn)新的相關(guān)的api
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
//1、找到指定服務(wù)的所有實(shí)例 A
List<Instance> instances = namingService.selectInstances(name, true);
//instances.get(0).getMetadata();//獲取實(shí)例的元數(shù)據(jù)
//2、過濾出相同集群下的所有實(shí)例 B
List<Instance> sameClustInstances = instances.stream()
.filter(instance -> Objects.equals(instance.getClusterName(), clusterName))
.collect(Collectors.toList());
//3、如果B是空,就用A
List<Instance> instancesToBeChosen = new ArrayList<>();
if(CollectionUtils.isEmpty(sameClustInstances)){
instancesToBeChosen = instances;
log.warn("發(fā)生跨集群的調(diào)用,name={},clusterName={},instances={}",name,clusterName,instances);
}else {
instancesToBeChosen = sameClustInstances;
}
//4、基于權(quán)重的負(fù)載均衡算法,返回1個實(shí)例
Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen);
log.info("選擇的實(shí)例是:port={},instance={}",instance.getPort(),instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("發(fā)生異常了,e={}",e);
return null;
}
}
}
//當(dāng)Balancer類下面的getHostByRandomWeight方法不能直接調(diào)用的時候,繼承它然后去調(diào)用
class ExtendBalancer extends Balancer{
public static Instance getHostByRandomWeight2(List<Instance> hosts) {
return getHostByRandomWeight(hosts);
}
}
配置application.yml
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
cluster-name: shanghai
配置NacosSameClusterWeightedRule
@Configuration
public class RibbonConfiguration {
//自定義負(fù)載均衡配置,通過Nacos client拓展Ribbon,進(jìn)行同一集群下服務(wù)優(yōu)先調(diào)用,這個是針對的異地災(zāi)備的
@Bean
public IRule ribbonRule(){
return new NacosSameClusterWeightedRule();
}
}
8、擴(kuò)展Ribbon,實(shí)現(xiàn)Nacos注冊中心基于元數(shù)據(jù)的版本控制
Nacos元數(shù)據(jù)的配置:
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
cluster-name: shanghai
metadata:
# 自己這個實(shí)例的版本
version: V1
# 允許調(diào)用的提供者版本
target-version: V1
新建NacosRule實(shí)現(xiàn)AbstractLoadBalancerRule
@Slf4j
public class NacosRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object o) {
try {
//負(fù)載均衡規(guī)則:優(yōu)先調(diào)用同一集群下,符合metadata元數(shù)據(jù)的實(shí)例
//如果沒有,就選擇所有集群下,符合metadata的實(shí)例
//1、查詢所有實(shí)例 A
//2、篩選元數(shù)據(jù)匹配的實(shí)例 B
//3、篩選出同cluster下元數(shù)據(jù)匹配的實(shí)例 C
//4、如果C為空,就用B
//5、隨機(jī)選擇實(shí)例
String clusterName = nacosDiscoveryProperties.getClusterName();
String targerVersion = nacosDiscoveryProperties.getMetadata().get("target-version");
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer)this.getLoadBalancer();
//想要請求的微服務(wù)名稱
String name = loadBalancer.getName();
//拿到服務(wù)發(fā)現(xiàn)新的相關(guān)的api
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
//所有實(shí)例
List<Instance> instances = namingService.selectInstances(name, true);
List<Instance> metadataMatchInstances = new ArrayList<>();
//如果配置了版本映射,那么只調(diào)用元數(shù)據(jù)匹配的實(shí)例
if(!StringUtils.isEmpty(targerVersion)){
metadataMatchInstances = instances.stream()
.filter(instance -> Objects.equals(targerVersion,instance.getMetadata().get("target-version")))
.collect(Collectors.toList());
if(CollectionUtils.isEmpty(metadataMatchInstances)){
log.warn("未找到元數(shù)據(jù)匹配的目標(biāo)實(shí)例!請檢查配置,目標(biāo)元數(shù)據(jù)配置為:targerVersion={}",targerVersion);
return null;
}
}
List<Instance> clusterMetadataMatchInstances = new ArrayList<>();
//如果配置了集群名稱,需篩選同集群下元數(shù)據(jù)匹配的實(shí)例
if(!StringUtils.isEmpty(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)用,name={},clusterName={},targerVersion={},instances={}",name,clusterName,targerVersion,instances);
}
}
Instance instance = ExtendBalancer.getHostByRandomWeight2(clusterMetadataMatchInstances);
log.info("選擇的實(shí)例是:port={},instance={}",instance.getPort(),instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("發(fā)生異常了,e={}",e);
return null;
}
}
}
負(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);
}
}
參考:
https://blog.csdn.net/wudiyong22/article/details/80829808
http://www.imooc.com/article/288674

