负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
如: List [0] instances = 127.0.0.1:8002
List [1] instances = 127.0.0.1:8001
8001+ 8002 组合成为集群,它们共计2台机器,集群总数为2, 按照轮询算法原理:
当总请求数为1时: 1 % 2 =1 对应下标位置为1 ,则获得服务地址为127.0.0.1:8001
当总请求数位2时: 2 % 2 =0 对应下标位置为0 ,则获得服务地址为127.0.0.1:8002
当总请求数位3时: 3 % 2 =1 对应下标位置为1 ,则获得服务地址为127.0.0.1:8001
当总请求数位4时: 4 % 2 =0 对应下标位置为0 ,则获得服务地址为127.0.0.1:8002
如此类推......
我这里是用作为Eureka的集群注册中心,
eureka
在你的提供服务的集群模块的Controller中加入:
@GetMapping(value = "/payment/lb")
public String getPaymentLB()
{
return serverPort;
}
在消费者微服务中也就是端口为80的模块做四件事:
1.ApplicationContextBean中去掉注解@LoadBalanced
@Configuration
public class ApplicationContextConfig
{
@Bean
// @LoadBalanced//用于寻找多个服务器,负载均衡
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
2.LoadBalancer接口
public interface LoadBalancer {
//创建接口方法
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
3.MyLB实现类
@Component
public class MyLB implements LoadBalancer{
//根据源码来写,此处得到AtomicInteger对象并赋初始值为0
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;//如果该值大于整型数最大值则赋0,防止溢出,否则next=current+1
}while (!this.atomicInteger.compareAndSet(current,next));//用的CAS的比较,目标值与原值不一致,则更新值,退出while循环
System.out.println("*****next"+next);
return next;
}
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index=getAndIncrement()%serviceInstances.size();//轮询算法,rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标
return serviceInstances.get(index);//取得下标为index的服务返回
}
}
4.OrderController类
@RestController
@Slf4j
public class OrderController
{
@Resource
private RestTemplate restTemplate;//注入RestTemplate对象
@Resource
private DiscoveryClient discoveryClient;//注入DiscoveryClient对象
@Resource
private LoadBalancer loadBalancer;//注入LoadBalancer对象
@GetMapping("/consumer/payment/lb")
public String getPaymentLB(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");//获取Eureka注册服务中心的服务名称为CLOUD-PAYMENT-SERVICE的服务集合
if(instances==null||instances.size()<=0){//如果没有就返回null
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);//调用我们自己写的轮询算法,得到调用的服务
URI uri = serviceInstance.getUri();//获取该服务的URL
return restTemplate.getForObject(uri+"/payment/lb",String.class);//转发访问
}