想要學(xué)習(xí)完整SpringCloud架構(gòu)可跳轉(zhuǎn): SpringCloud Alibaba微服務(wù)分布式架構(gòu)
Spring Cloud Ribbon是基于Netflix Ribbon實(shí)現(xiàn)的一套客戶(hù)端負(fù)載均衡的工具。
Ribbon是Netflix發(fā)布的開(kāi)源項(xiàng)目,主要功能是提供客戶(hù)端的軟件負(fù)載均衡算法和服務(wù)調(diào)用。
Ribbon客戶(hù)端組件提供一系列完善的配置項(xiàng)如連接超時(shí),重試等。
在配置文件中列出Load Balancer(簡(jiǎn)稱(chēng)LB)后面所有的機(jī)器,Ribbon會(huì)自動(dòng)的幫助你基于某種規(guī)則(如簡(jiǎn)單輪詢(xún),隨機(jī)連接等)去連接這些機(jī)器。
我們很容易使用Ribbon實(shí)現(xiàn)自定義的負(fù)載均衡算法。
1 SpringCloud Load Balance
LB負(fù)載均衡(Load Balance)是什么?
將用戶(hù)的請(qǐng)求平攤的分配到多個(gè)服務(wù)上,從而達(dá)到系統(tǒng)的HA(高可用)。常見(jiàn)的負(fù)載均衡有軟件Nginx,LVS,硬件F5等。
集中式LB Load Balance
即在服務(wù)的消費(fèi)方和提供方之間使用獨(dú)立的LB設(shè)施(可以是硬件,如F5,也可以是軟件,1如nginx),由該設(shè)施負(fù)責(zé)把訪(fǎng)問(wèn)請(qǐng)求通過(guò)某種策略轉(zhuǎn)發(fā)至服務(wù)的提供方;
Ribbon本地負(fù)載均衡客戶(hù)端 VS Nginx服務(wù)端負(fù)載均衡區(qū)別
Nginx是服務(wù)器負(fù)載均衡,客戶(hù)端所有請(qǐng)求都會(huì)交給Nginx,然后由Nginx實(shí)現(xiàn)轉(zhuǎn)發(fā)請(qǐng)求。即負(fù)載均衡是由服務(wù)端實(shí)現(xiàn)的。
Ribbon本地負(fù)載均衡,在調(diào)用微服務(wù)接口時(shí)候,會(huì)在注冊(cè)中心上獲取注冊(cè)信息服務(wù)列表之后緩存到JVM本地,從而在本地實(shí)現(xiàn)RPC遠(yuǎn)程服務(wù)調(diào)用技術(shù)。
2 總結(jié):
Ribbon其實(shí)就是一個(gè)軟負(fù)載均衡的客戶(hù)端組件,
他可以和其他所需請(qǐng)求的客戶(hù)端結(jié)合使用,和eureka結(jié)合只是其中的一個(gè)實(shí)例。
3 Ribbon工作流程:
Ribbon在工作時(shí)分成兩步:
- 第—步先選擇EurekaServer ,它優(yōu)先選擇在同一個(gè)區(qū)域內(nèi)負(fù)載較少的server.
- 第二步再根據(jù)用戶(hù)指定的策略,在從server取到的服務(wù)注冊(cè)列表中選擇一個(gè)地址。
- 其中Ribbon提供了多種策略:比如輪詢(xún)、隨機(jī)和根據(jù)響應(yīng)時(shí)間加權(quán)。
4 自定義Ribbon 負(fù)載均衡算法:
4.1 iRule接口:
4.2 Ribbon自帶的負(fù)載均衡算法:
com.netflix.loadbalancer.RoundRobinRule:
輪詢(xún)
com.netflix.loadbalancer.RandomRule:
隨機(jī)
com.netflix.loadbalancer.RetryRule:
先按照RoundRobinRule的策骼獲取服務(wù),如果獲取服務(wù)失敗則在指定時(shí)間內(nèi)會(huì)進(jìn)行重試,獲取可用的服務(wù)
weightedResponseTimeRule:
對(duì)RoundRobinRule的擴(kuò)展,響應(yīng)速度越快的實(shí)例選擇權(quán)重越大,越容易被選擇
BestAvailableRuleo:
會(huì)先過(guò)濾掉由于多次訪(fǎng)問(wèn)故障而處于斷路器跳閘狀態(tài)的服務(wù),然后選擇一個(gè)并發(fā)是最小的服務(wù)
vailabilityFilteringRule:
先過(guò)濾掉故障實(shí)例,再選擇并發(fā)較小的實(shí)例:
zoneAvoidanceRule
默認(rèn)規(guī)則,復(fù)合判斷server所在區(qū)域的性能和server的可用性選擇服務(wù)器
官方文檔明確給出了警告:
這個(gè)自定義配置類(lèi)不能放在@ComponentScan所掃描的當(dāng)前包下以及子包下,
否則我們自定義的這個(gè)配置類(lèi)就會(huì)被所有的Ribbon客戶(hù)端所共享,達(dá)不到特殊化定制的目的了。
4.3 負(fù)載均衡算法替代:
4.3.1、在非啟動(dòng)類(lèi)包及子包下創(chuàng)建配置類(lèi)
4.3.2、定義
/**
* Myrule : Ribbon 自定義負(fù)載均衡算法配置類(lèi)
*
* @author zyw
* @create 2023/6/18
*/
@Configuration
public class Myrule {
@Bean
public IRule getIRule(){
//定義為隨機(jī)
return new RandomRule();
}
}
4.3.3、啟動(dòng)類(lèi)增加RibbonClient注解
自定義需要指定的服務(wù)
/**
* OderMain80 :
*
* @author zyw
* @create 2023/6/16
*/
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOULD-PAYMENT-SERVICE",configuration = Myrule.class)
@MapperScan("com.zyw.springcloud.dao")
public class OderMain80 {
public static void main(String[] args) {
SpringApplication.run(OderMain80.class,args);
}
}
5 Ribbon負(fù)載均衡算法
5.1 輪詢(xún)算法原理:
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-579549.html
5.2 輪詢(xún)算法源碼:
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
public RoundRobinRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
//獲取有正常運(yùn)行的(可達(dá)的)服務(wù)集合
List<Server> reachableServers = lb.getReachableServers();
//獲取可負(fù)載服務(wù)集合
List<Server> allServers = lb.getAllServers();
//獲取有正常運(yùn)行的(可達(dá)的)服務(wù)的數(shù)量
int upCount = reachableServers.size();
//獲取可負(fù)載服務(wù)的數(shù)量 == 服務(wù)器集群總數(shù)量
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
//自旋鎖
//rest接口第幾次請(qǐng)求數(shù) % 服務(wù)器集群總數(shù)量 = 實(shí)際調(diào)用服務(wù)器位置下標(biāo),每次服務(wù)器重啟后rest接口計(jì)數(shù)從1開(kāi)始。
private int incrementAndGetModulo(int modulo) {
for (;;) {
//獲取當(dāng)前值
int current = nextServerCyclicCounter.get();
//計(jì)算下次值
int next = (current + 1) % modulo;
//比較并交換
if (nextServerCyclicCounter.compareAndSet(current, next))
//得到當(dāng)前下標(biāo)值
return next;
}
}
}
5.3 手寫(xiě)負(fù)載均衡算法
/**
* LoadBalancer : 自定義負(fù)載均衡算法
*
* @author zyw
* @create 2023/6/20
*/
public interface LoadBalancer {
//收集Eurek上所有活著的服務(wù)總數(shù)
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
/**
* MyLB : 自定義負(fù)載均衡算法實(shí)現(xiàn)類(lèi)
*
* @author zyw
* @create 2023/6/20
*/
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement() {
int currrnt;
int next;
do {
currrnt = this.atomicInteger.get();
//Integer.MAX_VALUE = 2147483647
next = currrnt >= 2147483647 ? 0 : currrnt + 1;
//自選鎖,直到得到期望值
} while (!this.atomicInteger.compareAndSet(currrnt, next));
System.out.println("第" + next + "次訪(fǎng)問(wèn)");
return next;
}
/**
* rest接口第幾次請(qǐng)求數(shù) % 服務(wù)器集群總數(shù)量 = 實(shí)際調(diào)用服務(wù)器位置下標(biāo),每次服務(wù)器重啟后rest接口計(jì)數(shù)從1開(kāi)始。
* @param serviceInstances
* @return
*/
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
/**
* OrderController : 訂單系統(tǒng)控制層
*
* @author zyw
* @create 2023/6/16
*/
@Slf4j
@RestController
@RequestMapping("consumer/orderController")
@Api(tags={"訂單系統(tǒng)控制層"})
public class OrderController {
@Resource
private RestTemplate restTemplate;
@Resource
private DiscoveryClient discoveryClient;
@Resource
private LoadBalancer loadBalancer;
@GetMapping("/lb")
@ApiOperation(value = "獲取負(fù)載服務(wù)的端口號(hào)", response = String.class)
public String getPaymentBl(){
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("CLOULD-PAYMENT-SERVICE");
if (serviceInstances == null || serviceInstances.size() <= 0){
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(serviceInstances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"paymentController/lb",String.class);
}
}
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-579549.html
到了這里,關(guān)于Ribbon 負(fù)載均衡服務(wù)調(diào)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!