springcloud ribbon 拦截resttemplate到实际请求调用源码讲解
spring cloud ribbon是一个基于HTTP 和 TCP 的客户端负载均衡工具,它基于Netflix Ribbon实现。通过spring cloud的封装,可以让我们轻松地将面向服务的REST模板请求自动转换成客户端负载均衡的服务调用。
在客户端负载均衡中,所有客户端节点都维护者自己要访问的服务端地址清单
在Ribbon中自带
随机规则:RandomRule
最可用规则: BestAvailableRule
轮询规则:RoundRobinRule
重试规则:RetryRule
客户端配置:ClientConfigEnabledRoundRobinRule
可用性过滤规则:AvailabilityFilteringRule
RT权重规则:WeightedResponseTimeRule
规避区域规则:ZoneAvoidanceRule
通过spring cloud ribbon的封装,我们在微服务架构中使用客户端负载均衡只需要如下两步:
1 服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心
2 服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用
版本 spring boot 1.5.14
LoadBalancerInterceptor 将一个普通的RestTemplate 变成客户端负载均衡 |
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; //由于我们在使用RestTemplate时采用了服务名作为host,所以直接从HttpRequest的URI对象中通过getHost, 就可以拿到服务名,然后调用execute函数去根据服务名来选择实例并发起实际的请求 @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 通过getServer 选取具体的服务器进行调用
request.apply 最后还是委派 spring 下 ClientHttpRequest 其调用过程是 LoadBalancerRequestFactory#apply --> InterceptingClientHttpRequest#execute --> InterceptingClientHttpRequest# org.springframework.http.client.ClientHttpRequest |
@Override public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException { ILoadBalancer loadBalancer = getLoadBalancer(serviceId); Server server = getServer(loadBalancer); RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server, serviceId), serverIntrospector(serviceId).getMetadata(server));
T returnVal = request.apply(ribbonServer); } |
RibbonLoadBalancerClient 下的 getServer(ILoadBalancer loadBalancer ) |
protected Server getServer(ILoadBalancer loadBalancer) { if (loadBalancer == null) { return null; } return loadBalancer.chooseServer("default"); // TODO: better handling of key } |
eureka 负载均衡器
在具体实现负载均衡是,是通过Ribbon 的 ILoadBalancer接口实现的
在默认情况下,ribbon 采用的是轮询的方式
调用链 |
默认: ZoneAwareLoadBalancer#chooseServer 调用父类 ---> BaseLoadBalancer#chooseServer ---> ZoneAvoidanceRule#choose |
ZoneAvoidanceRule#choose 方法,默认采用的是incrementAndGetModulo 即轮询 |
public Server choose(Object key) { ILoadBalancer lb = getLoadBalancer(); Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key); if (server.isPresent()) { return server.get(); } else { return null; } }
private int incrementAndGetModulo(int modulo) { for (;;) { int current = nextIndex.get(); int next = (current + 1) % modulo; if (nextIndex.compareAndSet(current, next) && current < modulo) return current; } } |
阅读更多
- SpringCloud 查找调用REST服务使用RestTemplate(ribbon负载)或feign模式 教程源码 火推
- spring cloud快速入门教程(五)进程间调用和微服务负载均衡(RestTemplate+Ribbon)
- SpringMVC RestTemplate的几种请求调用
- SpringMVC RestTemplate的几种请求调用
- 使用 Spring RestTemplate 调用 rest 服务时自定义请求头(custom HTTP headers)
- spring boot / cloud (八) 使用RestTemplate来构建远程调用服务
- 使用 Spring RestTemplate 调用 rest 服务时自定义请求头(custom HTTP headers)
- 笔记:Spring Cloud Ribbon RestTemplate 详解
- 玩转SpringCloud(F版本) 二.服务消费者(1)ribbon+restTemplate
- springcloud ribbon+rest的url请求失败
- Spring Cloud(服务的消费者 ribbon+restTemplate)
- spring boot / cloud (八) 使用RestTemplate来构建远程调用服务
- 玩转SpringCloud(F版本) 三.断路器(Hystrix)RestTemplate+Ribbon和Feign两种方式
- 《spring cloud微服务实战》读书笔记——Spring Cloud Ribbon(一)RestTemplate
- 为Spring Cloud Ribbon配置请求重试(Camden.SR2+)
- Spring Cloud EureKa Ribbon 服务注册-发现-调用
- 【图文经典版】声明式调用服务SpringCloud之Feign实例讲解
- 白话SpringCloud | 第四章:服务消费者(RestTemple+Ribbon+Feign)
- SpringCloud Cloud查找调用REST服务使用RestTemplate(ribbon负载) 或feign模式火推13
- Spring RestTemplate中几种常见的请求方式