负载均衡服务调用,Ribbon目前也进入维护模式。
一、Ribbon介绍
1.2、功能作用
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
算法 | 说明 |
---|---|
com.netflix.loadbalancer.RoundRobinRule | 轮询 |
com.netflix.loadbalancer.RandomRule | 随机 |
com.netflix.loadbalancer.RetryRule | 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试 |
WeightedResponseTimeRule | 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择 |
BestAvailableRule | 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 |
AvailabilityFilteringRule | 先过滤掉故障实例,再选择并发较小的实例 |
ZoneAvoidanceRule | 默认规则,复合判断server所在区域的性能和server的可用性选择服务器 |
2、修改负载均衡规则
修改cloud-consumer-order80
- 注意配置细节
这个自定义配置类不能放在主启动类@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊定制的目的了。 - 新建JdyRule规则类。
@Configuration public class JdyRule { @Bean public IRule myRule(){ return new RandomRule();//定义为随机 } }
主启动类添加@RibbonClient注解,实现使用Ribbon代替RestTemplate+@Loadbalanced的负载均衡规则。
@EnableEurekaClient @SpringBootApplication @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = JdyRule.class) public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class,args); } }
四、Ribbon负载均衡算法
4.1、原理
负载均衡算法:rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启后rest接口计数从1开始。
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); 如下: List[0] instance = 127.0.0.1:8081 List[1] instance = 127.0.0.1:8082 8081和8082组成集群,它们共计2台机器,集群总数为2,按照轮询算法原则: 当总请求数为1时:1%2=1对应下标位置为1,则获得的服务器地址为127.0.0.1:8081 当总请求数为1时:2%2=1对应下标位置为0,则获得的服务器地址为127.0.0.1:8082 当总请求数为1时:3%2=1对应下标位置为1,则获得的服务器地址为127.0.0.1:8081 当总请求数为1时:4%2=1对应下标位置为0,则获得的服务器地址为127.0.0.1:8082 以此类推....
4.2、自定义负载均衡器
1、环境准备
- 8001/8002微服务controller加
@GetMapping(value = "/payment/lb") public String getPaymentLB(){ return serverPort; }
- 80订单微服务改造:ApplicationContextBean去掉@LoadBalanced和@RibbonClient
2、编写自定义负载均衡器
- 定义接口
public interface LoadBalancer { //收集服务器总共有多少台能够提供服务的机器,并放到list里面 ServiceInstance instances(List<ServiceInstance> serviceInstances); }
- 参考Ribbon轮询源码实现MyLB
@Component public class MyLB implements LoadBalancer { private AtomicInteger atomicInteger = new AtomicInteger(0); //获得访问序号 private 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 instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
- 80订单微服务controller
@RestController @Slf4j public class OrderController { public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE"; @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient client; @Autowired private LoadBalance loadBalance; /** * 自定义负载均衡器 * @return */ @GetMapping(value = "/consumer/payment/lb") public String getPaymentLB(){ List<ServiceInstance> instances = client.getInstances("CLOUD-PAYMENT-SERVICE"); if (instances == null || instances.size() <= 0){ return null; } ServiceInstance serviceInstance = loadBalance.instances(instances); URI uri = serviceInstance.getUri(); return restTemplate.getForObject(uri+"/payment/lb",String.class); } }
3、测试
访问:http://localhost/consumer/payment/lb