美文网首页
Ribbon源码分析

Ribbon源码分析

作者: 昨日已逝去 | 来源:发表于2019-02-27 09:36 被阅读0次

Ribbon源码分析

原文在github,有些相对路径连接不能跳转,如想看原文项目地址 spingboot2.1.3加springcloud G版本,如果觉的不错给个star 谢谢!

带着想法读源码

当不使用@LoadBalanced时,会发生什么样的后果。

java.net.UnknownHostException: eureka-client-a
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184) ~[na:1.8.0_151]

从报错可以看出直接把服务名当成ip去请求,显然是找不到的。所以加上注解应该有代码拦截了这个请求,并把服务名转换成ip。

查看注解@LoadBalanced

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

注释写的很明显,标记一个restTemplete去配置LoadBlancerClient,那我们看下LoadBlancerClient

public interface LoadBalancerClient extends ServiceInstanceChooser {

    /**
     * Executes request using a ServiceInstance from the LoadBalancer for the specified
     * service.
     */
    <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;

    /**
     * Executes request using a ServiceInstance from the LoadBalancer for the specified
     * service.
     */
    <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;

    /**
     * Creates a proper URI with a real host and port for systems to utilize.
     * Some systems use a URI with the logical service name as the host,
     * such as http://myservice/path/to/service.  This will replace the
     * service name with the host:port from the ServiceInstance.
     */
    URI reconstructURI(ServiceInstance instance, URI original);
}
  • 使用LoadBalancer中的ServiceInstance执行指定的服务。
  • 创建一个带有真实主机和端口的URI,供系统使用。一些系统使用带有逻辑服务名称的URI作为主机,例如http://myservice/path/to/service。这将取代主机的服务名称:来自ServiceInstance的端口。

查看继承的接口

public interface ServiceInstanceChooser {

    /**
     * Chooses a ServiceInstance from the LoadBalancer for the specified service.
     * @param serviceId The service ID to look up the LoadBalancer.
     * @return A ServiceInstance that matches the serviceId.
     */
    ServiceInstance choose(String serviceId);
}
  • 从LoadBalancer中为指定的服务选择一个ServiceInstance。

LoadBalancerClient是一个接口,应该会有一个类配置它。在同包下有一个LoadBlancerAutoConfiguration。内容如下

@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
    //...
}

虽然没有看到直接生成LoadBalancerClient的bean。但是由注解可以看出这个类和LoadBalancerClient有一定的关联。仔细查看后里面有一段代码值得思考。

@Bean
public LoadBalancerInterceptor ribbonInterceptor(
        LoadBalancerClient loadBalancerClient,
        LoadBalancerRequestFactory requestFactory) {
    return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

发现把loadbalancerClient和请求放入一个拦截器中,联想到请可能被此处处理,查看拦截器代码

    @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));
    }

debug代码,继续往下走

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
    ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
    Server server = getServer(loadBalancer, hint);
    if (server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    }
    RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
            serviceId), serverIntrospector(serviceId).getMetadata(server));

    return execute(serviceId, ribbonServer, request);
}

发现ip的出现时RibbonLoadBalancerClient的execte下的getServer或的。
查看getServer

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
    if (loadBalancer == null) {
        return null;
    }
    // Use 'default' on a null hint, or just pass it on?
    return loadBalancer.chooseServer(hint != null ? hint : "default");
}

进入loadBalancer

    /**
     * Choose a server from load balancer.
     * 
     * @param key An object that the load balancer may use to determine which server to return. null if 
     *         the load balancer does not use this parameter.
     * @return server chosen
     */
    public Server chooseServer(Object key);
    

从注解可以看出是从负载均衡中挑出一个server,那负载均衡的具体实现就应该在实现类里面。而实现类调用的是ZoneAwareLoadBalancer
所以默认使用ZoneAwareLoadBalancer进行负载算法。
后续代码太过复杂,不做分析。

相关文章

  • Spring Cloud Ribbon 源码分析

    Spring Cloud Ribbon 源码分析 前言 原理介绍 ribbon提供了http请求负载均衡的能力,既...

  • Ribbon源码分析

    先看看@LoadBalanced注解: 这就是一个普通的标记注解,作用就是修饰RestTemplate让其拥有负载...

  • Ribbon源码分析

    介绍 先看下spring cloud官方对Ribbon的描述:Ribbon is a client-side lo...

  • Ribbon源码分析

    前言 这篇文章参考了Spring+Cloud微服务实战这本书。但是在此基础上延伸了很多知识点。 源码分析 @Loa...

  • Ribbon源码分析

    Ribbon源码分析 原文在github,有些相对路径连接不能跳转,如想看原文项目地址 spingboot2.1....

  • Ribbon结合Nacos的使用

    本次是ribbon结合Nacos的源码解析,Nacos的版本为2.2.8,ribbon和getway的源码还是相对...

  • 5、Ribbon

    一、Ribbon的核心组件IRule 二、Ribbon根据需要指定算法 Ribbon 的 负载均衡策略源码 Git...

  • Spring Cloud(七):Zuul

    Demo 源码下载 本案例为源码分支的 ribbon 分支 Ribbon 简介 分布式系统中,各个微服务会部署多个...

  • Spring Cloud Ribbon源码分析

    客户端负载均衡 学习spring cloud ribbon的时候不得不提到客户端负载均衡。在客户端负载均衡中,所有...

  • SpringCloud-源码分析 Ribbon

    本文作者:陈刚,叩丁狼高级讲师。原创文章,转载请注明出处。 本文章会通过断点跟踪的方式来解读 Ribbon 源码 ...

网友评论

      本文标题:Ribbon源码分析

      本文链接:https://www.haomeiwen.com/subject/vfhxuqtx.html