在平时使用Ribbon时,更多的是将Ribbon与RestTemplate相结合:算法
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
复制代码
首先定义一个RestTemplate,经过注解注入,同时注解也完成了负载均衡。bash
同时去使用restTemplate进行Rest调用负载均衡
@Override
public String hiService(String name){
return restTemplate.getForObject("http://SERVER-HI/hi?name="+name,String.class);
}
复制代码
那么在咱们在输入http://localhost:8770/hi?name=lixin后,到底作了什么dom
首先,在进行getForObject方法后,会将带入的url进行封装,封装成http请求request,而后被拦截器LoadBalancerInterceptor进行拦截,代码分别是:ide
@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);
}
复制代码
以及拦截部分:将request拦截下,截取其中URL及服务名,用于以后调用负载均衡方法时,选择合适的服务实例ui
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
复制代码
至此,调用RibbonLoadBalancerClient中的execute方法,先查看一下RibbonLoadBalancerClient类:this
其中LoadBalancerClient接口,有以下三个方法,其中excute()为执行请求,reconstructURI()用来重构url。url
ServiceInstanceChooser接口,主要有一个方法,用来根据serviceId来获取ServiceInstance。spa
它继承了ServiceInstanceChooser及LoadBalancerClient类,最终的负载均衡的请求处理,由它来执行线程
首先,去获取须要加载的负载均衡策略,经过getLoadBalancer方法执行,默认是轮询RoundRobbinRule方式:
在获取到负载均衡策略以后,经过getServer()方法去获取实例,点击进入getServer方法,发现是ILoadBalancer类去选择服务实例。
在ILoadBalancer接口中,addServers()方法是添加一个Server集合;chooseServer()方法是根据key去获取Server;markServerDown()方法用来标记某个服务下线;getReachableServers()获取可用的Server集合;getAllServers()获取全部的Server集合。
chooseServer则是由BaseLoadBalancer类进行实现:
根据代码能够看出,具体choose方法是根据不一样的负载均衡策略,会有不一样的选择方法,返回具体根据策略获得的服务实例。
最后根据服务实例,进行请求的调用。
IRule用于复杂均衡的策略,它有三个方法,其中choose()是根据key 来获取server,setLoadBalancer()和getLoadBalancer()是用来设置和获取ILoadBalancer的
IRule有不少默认的实现类,这些实现类根据不一样的算法和逻辑来处理负载均衡。Ribbon实现的IRule有如下几个。在大多数状况下,这些默认的实现类是能够知足需求的,若是有特性的需求,能够本身实现。
那咱们就先看看RoundRobbinRule类中的轮询策略:
可重试的轮询策略以下:
可见此处多了两行代码:
long requestTime = System.currentTimeMillis();
long deadline = requestTime + maxRetryMillis;
复制代码
定义了500ms的总重试时间,若是服务实例获取不到,则进入循环,在循环中每次须要判断一下是否超过总时间
while循环中,每次都会去获取一下服务实例,而后进行判断,若是实例仍然没有获取到,则对当前线程进行Thread.yield()操做,此操做的意义是:让出当前线程时间分片,从新争夺时间片,让定时任务去执行,看是否达到规定时间,如到时间,则执行interrupt()操做,退出循环
这便是可重试的策略
Ribbon + RestTemplate 的负载平衡,流程是: 经过注解后,对url进行封装request,拦截器对request进行拦截,而后根据负载均衡器去调用服务实例,完成负载平衡和服务调用