天天看點

手寫Ribbon負載均衡算法一、Ribbon有哪些自帶的負載均衡算法二、怎麼替換預設的負載均衡算法三、手寫負載均衡算法

一、Ribbon有哪些自帶的負載均衡算法

手寫Ribbon負載均衡算法一、Ribbon有哪些自帶的負載均衡算法二、怎麼替換預設的負載均衡算法三、手寫負載均衡算法

預設出廠設定用的是輪詢算法,就是每個服務清單按順序依次通路;

二、怎麼替換預設的負載均衡算法

首先注意一點,算法配置檔案不能處于@ComponentScan注解所在的包及其子包下,原因就不說了,自己百度去。

是以第一步,建立一個包com.xiexiaoyu.ribbon,然後建立一個配置類

@Configuration
public class MySelfRule
{
    @Bean
    public IRule myRule()
    {
        return new RandomRule();//定義為随機
    }
}
           

然後在主啟動類上加入注解

//通路CLOUD-PAYMENT-SERVICE服務時采用MySelfRule類中定義的負載均衡算法
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration=MySelfRule.class)
           

over,這樣就把這個客戶 端的負載均衡算法換成了随機通路算法

三、手寫負載均衡算法

1、ApplicationContextBean去掉注解@LoadBalance

ApplicationContextConfig用于傳回一個RestTemplate執行個體,用于rest接口調用。

@Configuration
public class ApplicationContextConfig
{
    @Bean
    //@LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}
           

2、手寫一個LoadBalance接口

1)LoadBalancer接口聲明傳回從一組微服務中傳回其中一個

public interface LoadBalancer
{
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
           

2)MyLB實作類實作LoadBalancer接口

@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;
    }

    //負載均衡算法:rest接口第幾次請求數 % 伺服器叢集總數量 = 實際調用伺服器位置下标  ,每次服務重新開機動後rest接口計數從1開始。
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances)
    {
        int index = getAndIncrement() % serviceInstances.size();

        return serviceInstances.get(index);
    }
}
           

3)Controller層調用負載均衡算法

微服務8001,注冊成CLOUD-PAYMENT-SERVICE:

@RestController
@Slf4j
public class PaymentController
{
	//server.port=8001 寫在配置檔案的,這裡不單獨列出了,不是本文重點
    @Value("${server.port}")
    private String serverPort;
    
    @GetMapping(value = "/payment/lb")
    public String getPaymentLB()
    {
        return serverPort;
    }
}
           

微服務8002,注冊成CLOUD-PAYMENT-SERVICE:

@RestController
@Slf4j
public class PaymentController
{
	//server.port=8002 寫在配置檔案的,這裡不單獨列出了,不是本文重點
    @Value("${server.port}")
    private String serverPort;
    
    @GetMapping(value = "/payment/lb")
    public String getPaymentLB()
    {
        return serverPort;
    }
}
           

服務消費者:

@RestController
@Slf4j
public class OrderController
{
	//微服務名稱
    public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private LoadBalancer loadBalancer;
    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping(value = "/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);
    }
}
           

完活!有興趣的可以自己實作IRule接口,然後配置負載均衡實作類為自己定義的IRule實作類