[TOC]java
以前咱们介绍了管理分布式组件注册的服务;eureka、consul、zookeeper、nacos他们均可以实现咱们服务的注册于获取。
可是实际咱们仍是须要咱们本身调用最终的客户端获取数据的。
localhost/order/payment/123
这个接看看响应是不是负载均衡的。ClientHttpRequestInterceptor
拦截器。@Bean public LoadBalancerInterceptor ribbonInterceptor( LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) { return new LoadBalancerInterceptor(loadBalancerClient, requestFactory); }
LoadBalanced
标准的RestTemplate。遍历全部RestTemplate诶个注入咱们LoadBalancerInterceptor拦截器。在这个拦截器内部会实现服务列表获取。而后负载均衡。LoadBalancerAutoConfiguration
配置类。经过名称咱们大概也能了解到这个类是配置负载均衡的自动配置类。Allows applications to transform the load-balanced {@link HttpRequest} given the chosen
org.springframework.beans.factory.annotation
包下。了解Spring的读者应该知道这是spring注入类的一种方式。关于spring注入方式解析咱们单独开篇分析下。这里咱们只用记住@Qualifier会注入相同属性的bean.SmartinitializingSingleton
和LoadBalancerRequestFactory
。关于LoadbalancerRequestFactory
这实际就是个工厂。在构造LoadBalancerIntercrptor
拦截器的时候须要用到。SmartInitializingSingleton
这个类。里面传了一个参数经过ObjectProvider封装的。ObjectProvider
的做用能够简单理解为@Autowired
。而内部的RestTemplateCustomer
就是咱们上文提到的做用是为了封装RestTemplate
。customizer.customize
就是调用添加拦截器了。RetryLoadBalancerInterceptor
拦截内部实现里实际上就是RetryTemplate和RestTemplate的区别。LoadBalancedRetryPolicy
设置的。public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor
spring
LoadBalancerInterceptor
这个拦截器不难发现。他就是实现了ClientHttpRequestIntrceptor
。这里咱们记住这个接口。在RestTemplate调用的时候确定会设计到ClientHttpRequestInterceptor
这个类。http://localhost/order/getpayment/123
。springboot
@Override @Nullable public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException { RequestCallback requestCallback = acceptHeaderRequestCallback(responseType); HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<>(responseType, getMessageConverters(), logger); return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables); }
InterceptingClientHttpRequestFactory
这个类中的createRequest方法上。InterceptingClientHttpRequest
对象会在拦截器部分阻塞。因此这里咱们不难看出上面Ribbon实现的LoadBalancerInterceptor。这个拦截器内部确定须要实现接口的调度。public interface LoadBalancerClient extends ServiceInstanceChooser { <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException; URI reconstructURI(ServiceInstance instance, URI original); }
ILoadBalancer
来实现负载均衡的。说实话笔者这里为了省事并无落实ILoadBalancer
和LoadBalancerClient
之间是如何绑定的。BaseLoadBalancer
对ILoadBalancer
的实现。里面重要的是chooseServer
这个方法。public Server chooseServer(Object key) { if (counter == null) { counter = createCounter(); } counter.increment(); if (rule == null) { return null; } else { try { return rule.choose(key); } catch (Exception e) { logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e); return null; } } }
RoundRobbinRule
中就是经过AtomicInteger原子类操做请求次数在于容器数量取模决定获取哪一个容器进行调用的。public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { List<Server> reachableServers = lb.getReachableServers(); List<Server> allServers = lb.getAllServers(); int upCount = reachableServers.size(); int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { log.warn("No up servers available from load balancer: " + lb); return null; } int nextServerIndex = incrementAndGetModulo(serverCount); server = allServers.get(nextServerIndex); if (server == null) { /* Transient. */ Thread.yield(); continue; } if (server.isAlive() && (server.isReadyToServe())) { return (server); } // Next. server = null; } if (count >= 10) { log.warn("No available alive servers after 10 tries from load balancer: " + lb); } return server; }
-Ribbon为咱们提供了不少中内置的负载均衡策略。经常使用的就是轮询。若是上述的不知足咱们也能够经过实现Irule来自定义策略规则。网络
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
来指定咱们的服务下负载策略。