Ribbon的使用
-
本地集群环境说明
consumer服务order(80)、 provider服务payment(8001、8002)、Eureka服务端(7001、7002)
-
Ribbon简介
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。 -
架构说明
Ribbon在工作时分成两步:
-
第一步先选择 EurekaServer ,它优先选择在同一个区域内负载较少的server.
-
第二步再根据用户指定的策略,在从server取到的服务注册列表中选择一个地址。
其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。
-
-
Ribbon的使用
单独引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
其他组件自动引入
spring-cloud-starter-netflix-eureka-client自带了spring-cloud-starter-ribbon引用。 -
核心组件IRule
规则实现类
规则说明:
规则替换
官方文档明确给出了警告:
这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,
否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。-
80服务中新建包myrule
-
80服务中创建规则类MyselfRule.class
@Configuration public class MyselfRule { @Bean public IRule myRule() { return new RandomRule();//定义为随机 } }
-
80服务中修改启动配置类,增加@RibbonClient注解,并标明规则类MyselfRule.class
@SpringBootApplication @EnableEurekaClient @RibbonClient(name = "cloud-payment-service",configuration = MyselfRule.class) public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class, args); } }
-
重新启动服务,发送请求验证负载均衡规则替换是否生效。
-
-
规则算法
-
轮询算法
负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。
List
instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); 如: List [0] instances = 127.0.0.1:8002
List [1] instances = 127.0.0.1:80018001+ 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
如此类推......
-
-
自定义规则
-
在8001、8002中新增接口方法,用于测试
@GetMapping(value = "/payment/lb") public String getPaymentLB() { return serverPort; }
-
80服务中的
ApplicationContextConfig.class
中去除@LoadBalanced
注解,以保证最终执行的是我们自定义的负载均衡算法。@Configuration public class ApplicationContextConfig { @Bean //@LoadBalanced//开启负载均衡 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
-
80服务新增LoadBalancer接口
public interface LoadBalancer { ServiceInstance instances(List<ServiceInstance> serviceInstances); }
-
80服务新增
LoadBalancer
接口实现类MyLB
@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; } //根据算法获取对应服务实例 @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index=getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
-
80服务controller中添加以下代码
@Resource private DiscoveryClient discoveryClient; @Resource private LoadBalancer loadBalancer; @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); }
-
依次启动服务,发送请求http://localhost/consumer/payment/lb验证
前端返回对应服务的端口号,后端日志如下:
即自定义算法运行成功。
-