zoukankan      html  css  js  c++  java
  • cloud server ribbon 自定义策略配置

    虽然ribbon默认为我们提供了多钟负载均衡策略,但有时候我们仍然需要自定义符合自身业务逻辑的规则

    使用配置文件的方式:我们只需要在配置文件中添加配置

    serviceId.ribbon.NFLoadBalancerRuleClassName=自定义的负载均衡策略类

    其中 serviceId 为具体服务名

    这样在调用对应服务时候,就会使用我们自定义的负载策略,很方便

    对于该配置文件springcloud是如何解析的呢,接下来我们就分析该配置为何生效

    引入关键类 RibbonClientConfiguration

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        @Bean
    @ConditionalOnMissingBean
    public IRule ribbonRule(IClientConfig config) {
        if (this.propertiesFactory.isSet(IRule.class, name)) {
            return this.propertiesFactory.get(IRule.class, config, name);
        }
        ZoneAvoidanceRule rule = new ZoneAvoidanceRule();
        rule.initWithNiwsConfig(config);
        return rule;
    }

    第一行:判断当前环境是否设置了IRule类

    1
    2
    3
    public boolean isSet(Class clazz, String name) {
            return StringUtils.hasText(getClassName(clazz, name));
        }

    getClassName 具体实现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    public String getClassName(Class clazz, String name) {
            if (this.classToProperty.containsKey(clazz)) {
                String classNameProperty = this.classToProperty.get(clazz);
                String className = environment.getProperty(name + "." + NAMESPACE + "." + classNameProperty);
                return className;
            }
            return null;
        }

    而classToProperty是啥呢

    1
    2
    3
    4
    5
    6
    7
    public PropertiesFactory() {
            classToProperty.put(ILoadBalancer.class, "NFLoadBalancerClassName");
            classToProperty.put(IPing.class, "NFLoadBalancerPingClassName");
            classToProperty.put(IRule.class, "NFLoadBalancerRuleClassName");
            classToProperty.put(ServerList.class, "NIWSServerListClassName");
            classToProperty.put(ServerListFilter.class, "NIWSServerListFilterClassName");
        }

    可以看到 其中有IRule.class对应 NFLoadBalancerRuleClassName

    回头看getClassName类

    1
    String className = environment.getProperty(name + "." + NAMESPACE + "." + classNameProperty);

    其中 name 为ribbon.client.name 也就是我们服务名,

    NAMESPACE 为 ribbon

    classNameProperty 为 NFLoadBalancerRuleClassName

    所以通过getClassName 方法 最终返回的是 我们系统中设置的 serviceId.ribbon.NFLoadBalancerRuleClassName 属性值

    接着看ribbonRule 第二行代码

    1
    <strong>return this</strong>.propertiesFactory.get(IRule.<strong>class</strong>, config, name);

    具体get实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public <c> C get(Class<c> clazz, IClientConfig config, String name) {
            String className = getClassName(clazz, name);
            if (StringUtils.hasText(className)) {
                try {
                    Class<!-- --> toInstantiate = Class.forName(className);
                    return (C) instantiateWithConfig(toInstantiate, config);
                } catch (ClassNotFoundException e) {
                    throw new IllegalArgumentException("Unknown class to load "+className+" for class " + clazz + " named " + name);
                }
            }
            return null;
        }</c></c>

    这样就很清晰了,最终会根据我们配置的负载策略类全路径 生成对应的实例

    而我们如果一个服务需要依赖调用N多服务的时候 采用这样的配置方式,显得有点繁琐,我们的负载配置不能全局化

    怎么处理呢?

    当然我们可以拓展org.springframework.cloud.netflix.ribbon.PropertiesFactory类 使其支持全局配置,但springcloud官方不推荐这样处理

    结合我们目前项目的处理方式,这里我给出另一条思路

    在配置文件中,我们添加一个属性

    loadbalanced.services = service-A,service-B

    另外添加一个RibbonLoadBalancerRuleConfiguration类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @Configuration
    @ConditionalOnClass(com.netflix.loadbalancer.ZoneAvoidanceRule.class)
    public class RibbonLoadbalancerRuleConfiguration implements InitializingBean {
     
        private final static Logger log = LoggerFactory.getLogger(RibbonLoadbalancerRuleConfiguration.class);
     
         
        @Value("#{'${loadbalanced.services}'.split(',')}")
        private List<string> loadbalancedServices;
         
        /**
         * 默认使用切流量的负载均衡策略
         */
        @Value("${ribbon.NFLoadBalancerRuleClassName}")
        private String ribbonLoadBancerRule;
     
        @Override
        public void afterPropertiesSet() throws Exception {
            if (null != loadbalancedServices)) {
                for (String service : loadbalancedServices)) {
                    String key = service + ".ribbon.NFLoadBalancerRuleClassName";
                    System.setProperty(key, ribbonLoadBancerRule);
                }
            }
        }
     
    }</string>

    这样在配置文件中我们只需要配置

    1
    2
    ribbon.NFLoadBalancerRuleClassName=自定义负载均衡策略
    loadBalancedService=需要使用自定义负载均衡策略的服务

    有时间会整理一篇更完整的ribbon负载均衡原理分析,敬请期待

  • 相关阅读:
    进程同步中的读者写者问题
    操作系统进程同步习题记录
    基于Python Flask的web日程管理系统
    面向对象第四单元及课程总结博客
    Vimtutor(中文版)学习笔记各章小结
    常用设计模式汇总说明
    图解Apache Mina
    Rocketmq 集群
    读《图解HTTP》有感-(HTTP首部)
    读《图解HTTP》有感-(与HTTP协作的WEB服务器)
  • 原文地址:https://www.cnblogs.com/lykbk/p/aseddsdsd32432434324234.html
Copyright © 2011-2022 走看看