Ribbon簡述
是什麼
spring cloud ribbon 是一套用戶端的負載均衡工具
主要用來:用戶端的軟體負載均衡算法和服務的調用
做什麼
負載均衡+RestTemplate調用
LB負載均衡:将使用者請求平攤到多個伺服器上,進而達到系統的HA(高可用)
ribbon是本地負載均衡:在調用微服務接口時,會在注冊中心中擷取注冊資訊服務清單之後緩存到jvm本地,進而在本地實作rpc的遠端調用;
nginx是伺服器負載均衡:用戶端所用請求交給nginx,然後由nginx實作轉發請求.即負載均衡是由服務端實作的。
Ribbon核心元件IRule
負載均衡方式
IRule接口實作類關系圖:

RoundRobinRule:輪詢
RandomRule:随機
RetryRule:先按照RoundRobinRule的政策擷取服務,如果擷取服務失敗則在指定時間内進行重試,擷取可用的服務
WeightedResponseTimeRule:對RoundRobinRule的擴充,響應速度越快的執行個體選擇權重越多大,越容易被選擇
BestAvailableRule:會先過濾掉由于多次通路故障而處于斷路器跳閘狀态的服務,然後選擇一個并發量最小的服務
AvailabilityFilteringRule:先過濾掉故障執行個體,再選擇并發較小的執行個體
ZoneAvoidanceRule:預設規則,複合判斷server所在區域的性能和server的可用性選擇伺服器
切換負載均衡方式
已知,當我們搭建好的Eureka微服務(參考Eureka
搭建微服務架構),預設的負載均衡方式是輪詢,本案例要做的是将預設的輪詢方式切換為随機方式。
pom
由于eureka自帶了 Ribbon的依賴,故我們不需要額外的引入。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
如何替換算法,把輪詢改為随機
官網明确警告:這個自定義配置類不能放在@componentScan所掃描的目前包以及子包下。否則我們的自定義配置類會被所有的Ribbon用戶端所共享,達不到特殊化制定的目的。(負載均衡方式,一般配置在消費者端,是以我們隻需要對消費者端的代碼做一下修改即可)
已知,@SpringBootApplication已經将@componentScan的注解引入,故此,我們不能将我建立的配置類被該注解掃描到
從我的代碼結構,可以看到,我的配置類MySelfRule建立的位置與主啟動類不在同步一包下的,這就避免了MySelfRule被掃描進去。
MySelfRule:
@Configuration
public class MySelfRule {
@Bean
public IRule myRule() {
// 定義為随機
return new RoundRobinRule();
}
}
主啟動類:
@SpringBootApplication
@EnableEurekaClient
//CLOUD-PAYMENT-SERVICE是服務注冊中心的服務名
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OraderMain80 {
public static void main(String[] args) {
SpringApplication.run(OraderMain80.class,args);
}
}
在主啟動類添加@RibbonClient。
自定義負載均衡
在平時的工作中,往往現有的負載均衡政策無法滿足需求,是以我們有必要了解如何自定義負載均衡。
要寫一個自定義的負載均衡,我們需要先了解負載均衡的原理。下面将通過刨析RoundRobinRule輪詢方式來深入了解。
RoundRobinRule的工作原理
由上述的配置類可知,我們若想切換一個新的負載均衡政策,我們隻需要改變配置類注冊bean的類型即可。如下:
@Configuration
public class MySelfRule {
@Bean
public IRule myRule() {
// 定義為随機
return new RandomRule();
}
}
是以,我們可以從這裡入手,要想自定義一個負載均衡政策,隻需要自行建立一個與RandomRule同性質的類并注入到容器中供即可。
什麼是同性質?
我們參考上述截圖,可見AbstractLoadBalancerRule抽象類之下有幾個實作類,分别對應了上述類圖關系的其中已有的負載均衡政策,而且他們都實作了相關的三個方法。從這裡可以發現,我們若要自定義一個負載均衡,完完全全可以參考該類的實作,隻需要将核心的實作方法替換一下就可以了,這裡就是我們可以從源碼看到的資訊。
(友情提示:有時候看源碼,不能單純的看,還要懂得會套用)
我們繼續看RandomRule實作:
public class RandomRule extends AbstractLoadBalancerRule {
/**
* Randomly choose from all living servers
*/
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
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) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
int index = chooseRandomInt(serverCount);
server = upList.get(index);
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
上面的源碼很簡單,也就是随機擷取一個服務int index = chooseRandomInt(serverCount);,getLoadBalancer()方法是父類的實作,是以我們隻需要看choose(ILoadBalancer lb, Object key)方法的實作即可。(我們也可以想到,我們自定義的負載均衡類,也隻重點實作該方法即可)
至此,沒什麼好說的,看到這我們已經知道要實作一個自定義的負載均衡政策,已經很明了了。好人做到底,随便貼一下輪詢方式的算法原理:
自定義負載均衡實作
如上述截圖,具體隻需要參考實作抽象類的核心方法就可以了。