Ribbon負載均衡服務調用
一、Ribbon概述
1、是什麼
Spring Cloud Ribbon 是基於Netflix Ribbon實現的一套客戶端負載均衡工具。主要功能是提供客戶端的軟件負載均衡算法和服務調用。
官網
Ribbon現在已經進入維護模式
未來替換方案:
Spring Cloud Starter Loadbalancer
2、能幹嘛
主要做負載均衡
Ribbon和Nginx的區別
1)集中式LB
即在服務的消費方和提供方之間使用獨立的LB設施(可以是硬件,如F5,也可以是軟件,如Nginx),由該設施負責把訪問請求通過某種策略轉發至服務的提供方;
2)進程內LB
將LB邏輯集成到消費方,消費方從服務註冊中心獲知有哪些地址可用,然後自己再從這些地址中選擇一個合適的服務器
Ribbon 就屬於進程內LB,它只是一個類庫,集成於消費方進程,消費方通過它來獲取到服務提供方的地址。
3)總結
前面講過了80通過輪詢負載訪問8001/8002
一句話——負載均衡+RestTemplate調用
二、Ribbon負載均衡演示
1、架構說明
總結:Ribbon其實就是一個軟負載均衡的客戶端組件,它可以和其他所需請求的客戶端結合使用,和eureka結合只是其中的一個實例
Ribbon在工作時分成兩步
第一步選擇EurekaServer ,它優先選擇在同一個區域內負載較少的server。
第二步再根據用戶指定策略,在從server取到的服務註冊列表中選擇一個地址。
其中Ribbon提供了多種策略:比如輪詢、隨機和根據響應時間加權。
2、pom
spring-cloud-starter-netflix-eureka-client
默認已經和Ribbon整合
查看源碼:
不需要再次引入Ribbon的依賴
3、二說RestTemplate
1)官網
2)getForObject方法/getForEntity方法
區別:
getForObejct() 返回對象爲響應體重數據轉化成的對象,基本上可以理解爲Json
getForEntity() 返回對象爲ResponseEntity對象,包含了響應中的一些重要信息,比如響應頭、響應狀態碼、響應體等。
3)postForObject/postForEntity
4)GET請求方法
5)POST請求方法
三、Ribbon核心組件IRule
1、IRule:根據特定算法中從服務列表中選取一個要訪問的服務
1)com.netflix.loadbalancer.RoudRrobinRule——輪詢
2)com.netflix.loadbalancer.RandomRule——隨機
3)com.netflix.loadbalancer.RetryRule——先按照RoundRobinRul的策略獲取服務,如果獲取服務失敗則在指定時間內會進行重試,獲取可用服務
4)WeightedesponseTimeRule——對RoundRobinRule的擴展,響應速度越快的實例選擇權重越大,越容易被選擇
5)BestAvailableRule——會先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,然後選擇一個併發量最下的服務
6)AvailabilityFilteringRule——先過濾掉故障實例,在選擇併發量較小的實例
7)ZoneAvoidanceRule——默認規則,複合判斷server所在區域的性能和server的可用性選擇服務器
2、如何替換
1)修改cloud-consumer-order80
2)注意配置細節
官方文檔明確給出了警告:
這個自定義配置類不能放在@ComponentScan所掃描的當前包下以及子包下,否則我們自定義的這個配置類就會被所有的Ribbon客戶端所共享,達不到特殊化定製的目的了。
![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200404105047740.png?
3)新建package(com.atguigu.myrule)
4)上面包下新建MySelfRule規則類
package com.atguigu.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule();//定義爲隨機
}
}
5)主啓動類添加@RibbonClient
package com.atguigu.springcloud;
import com.atguigu.myrule.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
6)測試
http://localhost/consumer/payment/get/35
四、Ribbon負載均衡算法
1、原理
負載均衡算法:rest接口第幾次請求數%服務器集羣總數量=實際調用服務器位置下標,每次服務重啓動後rest接口技術從1開始
2、源碼
PS:
CAS(compare and swap)自旋鎖,就是操作後會判斷內存值是否跟預期值一致,是則替換。
3、手寫
自己寫一個本地負載均衡器試試
1)7001/7002集羣啓動
2)8001/8002微服務改造——Controller
@GetMapping("/payment/lb")
public String getPaymentLB(){
return serverPort;
}
3)80訂單微服務改造
1、註釋掉@LoadBalanced註解
2、LoadBalancer接口
package com.atguigu.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import java.util.List;
public interface LoadBalancer {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
3、MyLB
package com.atguigu.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger=new AtomicInteger(0);
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;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
4、OrderController
@Resource
private LoadBalancer loadBalancer;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/consumer/payment/lb")
public String getPaymentLB(){
List<ServiceInstance> instances=discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if(instances==null||instances.size()<=0){
return null;
}
ServiceInstance serviceInstance=loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
5、測試
http://localhost/consumer/payment/lb