1. 程式人生 > 其它 >學習筆記【SpringCloud-第五節:Ribbon負載均衡服務呼叫】

學習筆記【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