カスタム負荷等化ポーリングアルゴリズム-Ribbonベースのポーリングアルゴリズム


一:LoadBalanceインタフェースのカスタマイズ
具体的なコードは以下の通りです.
package com.springcloudtest.order.config;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

public interface LoadBalance {
     

    ServiceInstance instances(List<ServiceInstance> serviceInstanceList);

}


このインタフェースには、次の2つの機能があります.
	1.    ,            ,         instances  ,       List,
	                    
	2.             ,                 ,       ,     
	           

二:負荷均衡ポーリングアルゴリズムを採用してこのインタフェースを実現する
1.上のLoadBalanceインタフェースを実現する
package com.springcloudtest.order.config;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class MyLoadBalance implements  LoadBalance {
     
    public ServiceInstance instances(List<ServiceInstance> serviceInstanceList) {
     

        return  null;
    }
}

注意:
	  @Component,        IOC   ,     @Resource  

2.CAS+スピンロック方式でポーリングアルゴリズムを実現
package com.springcloudtest.order.config;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class MyLoadBalance implements  LoadBalance {
     

    //    Integer,                 
    private AtomicInteger atomicInteger = new AtomicInteger(0);


    /**
     *   CAS +                    
     * @return
     */
    public final  int getServiceCallSubscript(){
     
        //   
        int current;
        //   
        int next;
        //   
        do{
     
            //     
            current = this.atomicInteger.get();
            next = current >=Integer.MAX_VALUE ? 0 :current+1;
            //CAS       ,            ,          
        }while (!this.atomicInteger.compareAndSet(current,next));
        System.out.println("next:--------"+next);
        return next;
    }


    public ServiceInstance instances(List<ServiceInstance> serviceInstanceList) {
     
  
        return  null;
    }
}


CAS+スピンロックを採用する理由:負荷等化で使用するシーンは高同時性であるため、ポーリングアルゴリズムの核心は1つの整数型の下付き文字を得ることであり、高同時性のシーンの下で、この下付き文字のデータの一致性を保証する必要があり、CASはこの下付き文字のデータの一致性を保証することができ、スピンロックはこの要求の絶え間ないアクセスを成功するまで再試行することができる.CAS+スピンロックは、高効率かつ安全性の下でマイクロサービスの高可用性を保証できるためである.
——————————————————————————————————————
 //    Integer,                 
    private AtomicInteger atomicInteger = new AtomicInteger(0);

AtomicIntegerを採用した理由:
          ,                     ,             
    ,   CAS   

——————————————————————————————————————
this.atomicInteger.compareAndSet(current,next)

CAS操作
comapreAndSet     comapreAndSwap,                       ,
            (             ),               ,     
          ,              

——————————————————————————————————————
     do{
     
            //     
            current = this.atomicInteger.get();
            next = current >=Integer.MAX_VALUE ? 0 :current+1;
            //CAS       ,            ,          
        }while (!this.atomicInteger.compareAndSet(current,next));
        System.out.println("next:--------"+next);
        return next;
    }

スピンロック:
            ,     do....while  ,         ,         CAS
   ,                    ,         ,             
current = this.atomicInteger.get();

Currentは、現在の下付き文字を取得し、CASの比較に使用します.
next = current >=Integer.MAX_VALUE ? 0 :current+1;

nextの付与には3つの演算子が使用され、サービス呼び出しの回数が整数の最大値を超えると0にリセットされます.そうしないと、現在の下付き文字の値を変更するために1つ追加されます.
2.このポーリングアルゴリズムによって生成された値を取得し、パラメータマイクロサービスインスタンスListの下付き
    public ServiceInstance instances(List<ServiceInstance> serviceInstanceList) {
     
        //           
        int index = getServiceCallSubscript()%serviceInstanceList.size();
        //    serviceInstanceList       ServiceInstance  
        return  serviceInstanceList.get(index);
    }

呼び出しが必要なマイクロサービスインスタンスの下のラベルを取得するには、余剰取得法を使用します.
  : index = current %        
index   List     
current             
          List   

最後に、この下付き文字で取得したインスタンスを返します.
三:この負荷等化ポーリング方法を呼び出して負荷等化を実現する
package com.springcloudtest.order.controller;

import com.springcloudtest.order.config.LoadBalance;
import com.springcloudtest.order.config.MyLoadBalance;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URI;
import java.util.List;

@Controller
public class TestController {
     

    @Value("${server.port}")
    private String serverPort;
    @Resource
    private LoadBalance myLoadBalance;
    @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private RestTemplate restTemplate;
    
    @RequestMapping("/order/myLoadBalance")
    @ResponseBody
    public  String myLoadBalance(){
     
        //      payment-springcloud      List
        List<ServiceInstance> serviceInstanceList  =  discoveryClient.getInstances("payment-springcloud");
        //      List  ,             ,  null
        if(CollectionUtils.isEmpty(serviceInstanceList)){
     
            return null;
        }
        //  List           ,           
        ServiceInstance serviceInstance = myLoadBalance.instances(serviceInstanceList);
        //          
        URI uri = serviceInstance.getUri();

        return  restTemplate.postForObject(uri+"/payment/consul",null,String.class);

    }
}


具体的な手順:
1.  payment-springcloud          List
2.                 instances  ,           
3.       URI  ,  restTemplate      ,        

注意:1.discoveryClientというオブジェクトを取得するには、アプリケーション起動クラスに@EnableDiscoveryClient注記を追加する必要があります2.restTemplateというオブジェクトを取得するには、まずrestTemplateというオブジェクトを注入する必要があります