學習筆記【SpringCloud-第五節:Ribbon負載均衡服務呼叫】
技術標籤:# SpringCloudjava
Ribbon
Spring Cloud Ribbon是基於Netflix Ribbon實現的一套客戶端 負載均衡的工具
簡單的說,Ribbon是Netflix釋出的開源專案,主要功能是提供客戶端的軟體負載均衡演算法與服務呼叫。簡單的說,就是砸死配置檔案中列出Load Balancer(簡稱LB)後面的所有的及其,Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連線等)去連線這些及其。我們很容易使用Ribbon實現自定義的負載均衡演算法。
LB負載均衡是什麼
簡單的說就是將使用者的請求分攤到多個服務上,從而達到系統的HA(高可用)。常見的負載均衡有軟體Nginx,LVS,硬體F5等
Ribbon本地負載均衡客戶端與Nginx服務端負載均衡區別
Nginx是伺服器負載均衡,客戶端所有請求都會交給nginx,然後由nginx實現轉發請求。即負載均衡是由服務端實現的
Ribbon本地負載均衡,在呼叫微服務介面時候,會在註冊中心上獲取註冊資訊服務裂變之後混存到JVM本地,從而在本地實現RPC遠端服務呼叫技術
Eureka中已經整合了Ribbon,可以直接加註解
二說RestTemplate的使用
getForObject:
返回物件為響應體中資料轉化成的物件,基本上可以理解為Json
@GetMapping("/consumer/payment/get/{id}" )
public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
getForEntity:
返回物件為ResponseEntity物件,包含了響應中的一些重要資訊,比如響應頭、響應狀態碼、響應體等
@GetMapping("/consumer/payment/getForEntity/{id}" )
public CommonResult<Payment> getPayment2(@PathVariable("id") Long id){
ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
if (entity.getStatusCode().is2xxSuccessful()) return entity.getBody();
else return new CommonResult<>(444,"操作失敗");
}
Ribbon核心元件IRule:
- com.netflix.loadbalancer.RoundRobinRule輪詢
- com.netflix.loadbalancer.RandomRule隨機
- com.netflix.loadbalancer.RetryRule先按照輪詢的策略獲取服務,如果獲取服務失敗則在指定時間內會進行重試,獲取可用的服務
- WeigrhtResponseTimeRule對輪詢的擴充套件,響應速度越快的例項選擇權重越大,越容易被選擇
- BestAvailableRule會先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,然後選擇一個併發量最小的服務
- AvailabilityFilteringRule先過濾故障例項,在選擇併發較小的例項
- ZoneAvoidanceRule預設規則,符合判斷server所在區域的效能和server的可用性選擇伺服器
規則:
不能被@ComponentScan掃描到,所以我們這裡新建一個myrule包
定義自己的規則類:
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule();//定義為隨機
}
}
在主啟動類上加@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);
}
}
負載均衡演算法
輪詢演算法:
rest介面第幾次請求數%伺服器叢集總數量=實際呼叫伺服器位置下標,每次伺服器重啟動後rest介面計數從1開始。
手寫輪詢演算法:
8001、8002的controller:
@GetMapping(value = "/payment/lb")
public String getPaymentLB(){
return serverPort;
}
註釋掉原來的負載均衡@LoadBalanced
建個包,寫個介面
public interface LoadBalancer {
ServiceInstance instance(List<ServiceInstance> serviceInstances);
}
寫實現類
@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 instance(List<ServiceInstance> serviceInstances) {
int index=getAndIncrement()%serviceInstances.size();
return serviceInstances.get(index);
}
}
在controller中引入
@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.instance(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
注意一定要註釋掉原來的@LoadBalanced