SpringCloud 8 Ribbon负载均衡服务调用
一 概述
二、官网资料
https://github.com/Netflix/ribbon/wiki/Getting-Started
三、能干嘛
2、集中式LB与进程内LB区别
总结:负载均衡+RestTemplate调用
四、Ribbon负载均衡演示
官网:
https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
getForObject方法/getForEntity方法
postForObject/postForEntity
五、Ribbon核心组件IRule
IRule:根据特定算法从服务列表中选取一个要访问的服务
六、修改代码
1 添加规则类:
注意: 官方文档明确给出了警告:
这个自定义配置类不能放在 @ComponentScan 所扫描的当前包下以及子包下,否则自定义的配置类就会被所有的 Ribbon 客户端所共享,达不到特殊化定制的目的了
1、MySelfRule代码:
package com.atguigu.myrule;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 自定义负载均衡规则类
*/
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule();
}
}
2 主启动类添加 @RibbonClient
在启动该微服务的时候就能去加载我们的自定义 Ribbon 配置类,从而使配置生效
package com.atguigu.springcloud;
import com.atguigu.myrule.MySelfRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PROVIDER-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
3 测试
多次刷新,是随机出现 serverPort ,负载规则就更改为随机了。
注意:
OrderController代码中配置字段信息要与OrderMain80启动类代码中@RibbonClient(name)保持一致
七、Ribbon负载均衡算法
负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启后rest接口计数从1开始。
原码
package com.netflix.loadbalancer;
public interface IRule{
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
手写:原理+JUC(CAS+自旋锁复习)
(1)7001/7002集群启动、
(2)8001/8002微服务改造、【Controller】
// 增加以下代码
...
@GetMapping(value = "/payment/lb")
public String getPaymentLB(){
return serverPort;
}
...
(3)80客户端改造、【Controller】
LoadBalancer 接口代码
package com.jiao.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import java.util.List;
public interface LoadBalancer {
ServiceInstance instances(List serviceInstances); //通过serverName找serverPort
}
MyLb【也就是LoadBalancerImpl】
package com.jiao.springcloud.lb;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class MyLb implements LoadBalancer{
private AtomicInteger atomicInteger = new AtomicInteger(0); //初始为0
private final int getAndIncrement(){
int current;
int next;
do {
current = this.atomicInteger.get(); //0
next = current >= 2147483647 ? 0 : current + 1;
}while (!this.atomicInteger.compareAndSet(current,next)); //自旋:当前值=期望值:修改值
System.out.println("*****第几次访问next:"+next);
return next;
}
public ServiceInstance instances(List serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
OrderController 增加代码
...
@Resource
private LoadBalancer loadBalancer; //自己写的负载均衡算法
@Resource
private DiscoveryClient discoveryClient;
...
@GetMapping(value = "/consumer/payment/lb")
public String getPaymentLB(){
List 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);
}
测试【http:localhost/consumer/payment/lb】
注意:要配置服务名称(“CLOUD-PAYMENT-SERVICE”)
对应代码下载地址:Ribbon