服务调用 Ribbon
Spring Cloud Ribbon是Netflix Ribbon实现的一套客户端,主要功能是提供客户端软件负载均衡算法和服务调用。Ribbon客户端提供一系列完善的配置如连接超时,重试等。就是在配置文件中列出Load Balancer后面的所有机器,Ribbon会自动帮你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们能很容易的使用Ribbon实现自定义的负载均衡算法。
Ribbon负载均衡和Rest调用:
1.Eureka客户端或者Feign的依赖中已经引入Ribbon的依赖(也可单独引入)
2.配置类中给容器注入RestTemplate
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
3.在Controller层注入RestTemplate
@Resource private RestTemplate restTemplate; public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
4.调用服务方法
restTemplate.getForObject(url, responseType);
restTemplate.postForObject(url, request, responseType);
Ribbon负载均衡:(默认负载均衡策略是轮询)
1.添加负载均衡策略的配置类
@Configuration public class MySelfRule { @Bean public IRule myRule(){ new RoundRobinRule(); // 轮询,默认的负载均衡策略 new RandomRule(); // 随机获取服务 new RetryRule(); // 按照轮询获取服务,指定时间内失败会重试 new WeightedResponseTimeRule(); // 按权重选择服务 new BestAvailableRule(); // 先过滤不可用服务,然后选择并发量最小的服务 new AvailabilityFilteringRule(); // 先过滤故障实例,再选择并发较小的实例 new ZoneAvoidanceRule(); // 综合判断server所在区域的性能,和server的可用性 return new MyRule(); } }
注意:Ribbon的负载均衡的配置类不能放再主启动类所在的包或子包
2.在主启动类上添加 @RibbonClient 注解
@SpringBootApplication @EnableEurekaClient @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class) public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class, args); } }
注意:@RibbonClient 的name属性指定的服务名需要与注册中心中的服务名称一致(大写)
自定义轮询策略方式一
1.新建一个轮询规则类继承 AbstractLoadBalancerRule 类去重新 choose() 方法
@Slf4j public class MyRule2 extends AbstractLoadBalancerRule { private AtomicInteger atomicInteger = new AtomicInteger(0); @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } @Override public Server choose(Object key) { ILoadBalancer lb = getLoadBalancer(); Server server = null; if (lb != null) { List<Server> allServers = lb.getAllServers(); int serverCount = allServers.size(); if (serverCount != 0) { int nextServerIndex = incrementAndGetModulo(serverCount); server = (Server) allServers.get(nextServerIndex); } } return server; } // 自旋锁获取服务列表的下标值 private int incrementAndGetModulo(int serverCount) { int current; int next; do { current = this.atomicInteger.get(); next = (current + 1) % serverCount; } while(!this.atomicInteger.compareAndSet(current, next));return next; } }
2.在Ribbon的负载均衡配置类中注入IRule时候使用刚刚自定义的类
@Configuration public class MySelfRule { @Bean public IRule myRule(){ return new MyRule2(); } }
自定义轮询策略方式二
1.定义LoadBalancer接口
public interface LoadBanlacer { ServiceInstance getInstance(List<ServiceInstance> serviceInstances); }
2.定义MyLB类实现LoadBalancer接口实现getInstance()方法
@Component public class MyLB implements LoadBanlacer { private AtomicInteger atomicInteger = new AtomicInteger(0); public final int getAndIncrement() { int current; int next; do { current = this.atomicInteger.get(); next = current >= Integer.MAX_VALUE ? 0 : current + 1; } while (!this.atomicInteger.compareAndSet(current, next)); System.out.println("***访问次数****next="+next); return next; } @Override public ServiceInstance getInstance(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
3.注入 LoadBalancer 与 DiscoveryClient 对象
4.调用服务
@GetMapping("/consumer/payment/lb") public String getPaymentLB(){ List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); if (instances == null || instances.size() <= 0) { return null; } ServiceInstance instance = loadBanlacer.getInstance(instances); URI uri = instance.getUri(); return restTemplate.getForObject(uri+"/payment/lb", String.class); }
作者:[一柒微笑]