Netflix Ribbon的阅读理解

作者: 化简为繁 | 来源:发表于2016-12-30 15:12 被阅读0次

    最近用到Ribbon,总是觉得Ribbon既强大但是又不好用,其实根源还是对其内部的工作原理不够了解,导致对一些现象不能给出合理的解释,也影响了功能扩展。希望通过本次梳理,能够对Ribbon有一个较为清晰的理解!最近记性也不好了,还是要写下来才有印象。。。-_-

    Ribbon + Spring Cloud

    Ribbon是Netflix开源的一款用于客户端软负载均衡的工具软件。
    Spring Cloud对Ribbon进行了一些封装以更好的使用Spring Boot的自动化配置理念。

    先建个环境跑起来

    • 搭建一个基本的Spring Boot项目
    • 引入Spring Cloud Zuul依赖(Zuul直接包含了Ribbon的依赖,省点事。。。)
    <dependency>    
       <groupId>org.springframework.cloud</groupId>  
       <artifactId>spring-cloud-starter-zuul</artifactId>   
       <version>1.2.3.RELEASE</version>
    </dependency>
    
    • 启用Zuul
    @SpringBootApplication
    @EnableZuulProxy
    public class ZuulApplication {
        public static void main(String[] args) {    
            SpringApplication.run(ZuulApplication.class, args);
        }
    }
    
    • 配置路由
    server:  
        port: 7777
    zuul:  
        routes:   
           node:
               path: /api/**
               serviceId: node
    ribbon: 
       eureka:
          enabled: false
    node: 
        ribbon:
          listOfServers: http://localhost:9600,http://localhost:9500
    

    OK,访问http://localhost:7777/api/hello,就可以看到请求在9500和9600间不停切换了。

    我在9500,9600启动了两个node express server, 只接受'/hello'请求,返回'Hello,world! {port}'

    看看源码

    如上,Ribbon发挥了负载均衡的作用,从结果来看,目前ribbon是使用轮询的方式进行负载均衡。为了更好的理解,还是看看代码,他到底怎么工作的?

    入口

    查看spring-cloud-netflix-core-1.2.3.RELEASE.jar/META-INF/spring.fatories文件:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration,
    ...
    org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration,\
    

    很明显,RibbonAutoConfiguration就是Spring Boot启动Rabbion的入口配置类。

    RibbonAutoConfiguration

    public class RibbonAutoConfiguration {
    ...
     @Bean
     public SpringClientFactory springClientFactory() {   
         SpringClientFactory   factory = new SpringClientFactory();  
         factory.setConfigurations(this.configurations);   return factory;}
    ...
    }
    

    很明显,最重要的bean就是SpringClientFactory, 为啥?因为其他bean都需要他去初始化。。。

    SpringClientFactory

    方法列表如图:


    SpringClientFactory.png

    查看方法列表,此类提供了获取指定serviceId的IClient, ILoadBalance, ILoadBalanceContext等对象的重要方法。

    • IClient 是发起请求并执行的接口,先不管;
    • ILoadBalanceContext 封装了一些负载均衡额外的方法,比如noteOpenConnection(), noteError(), noteResponse()等等,先不管。
    • ILoadBalance就是我想知道的负载均衡啦。

    仔细查看获取LB(LoadBalance)实例的方法,发现LB实例最终从父类NamedContextFactory获取Bean。
    Bean来源AnnotationConfigApplicationContext context ,

    public <T> Map<String, T> getInstances(String name, Class<T> type) {
       AnnotationConfigApplicationContext context = getContext(name);   
        if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) {    
          return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);   
        }   
        return null;
    }
    

    这个Context从那里获取我想要的bean实例呢?还是截图吧,这个鬼排版傻死了。

    createContext

    看看context的创建过程,上面的红圈处,它会尝试为每个serviceId使用属于自己的配置类(当然前提是你有对应的配置),并注册;
    下面的红圈说明,它会注册一个默认的配置类this.defaultConfigType,

    this.defaultConfigType = RibbonClientConfiguration.class;
    context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
    

    至此,一个关键的配置类被发现了:RibbonClientConfiguration, 不容易-_-!

    RibbonClientConfiguration

    方法列表:


    Paste_Image.png

    基本上看着方法名就知道各种Bean是干什么的吧(IRule,IPing,ServerList,ILoadBalancer,ServerListFilter,RibbonLoadBalancerContext,RetryHandler,ServerIntrospector)。
    更重要的是:我们可以大胆的为每个serviceId指定自己的配置类了,如下,为"node"指定IPing的特殊的实现类:

    @RibbonClient(name = "node", configuration = NodeServiceConfig.class)
    public class ZuulApplication {
    ...
    }
    
    public class NodeServiceConfig {  
      private String name = "node";   
      @Autowired    
      private IClientConfig iClientConfig;   
      @Bean    
      public IPing ribbonPing(IClientConfig iClientConfig) {    
          if (this.propertiesFactory.isSet(IPing.class, name)) {            
              return this.propertiesFactory.get(IPing.class, iClientConfig, name);       
           }        
          return new NoOpPing();   
       }
    }
    

    未完待续...

    相关文章

      网友评论

        本文标题:Netflix Ribbon的阅读理解

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