您现在的位置是:首页 >技术交流 >ribbon的执行原理_3(自定义过滤规则)网站首页技术交流

ribbon的执行原理_3(自定义过滤规则)

宽仔的编程之路 2023-05-31 12:00:01
简介ribbon的执行原理_3(自定义过滤规则)

ribbon的执行原理_2 文章中详细分析了ribbon选择负载均衡器并进行执行的过程,本篇文章就实现自定义服务过滤功能来做详细的分析

场景

  1. 灰度和生产的服务都部署在同一个注册中心
  2. 生产环境的服务只能调用生产环境的微服务
  3. 灰度环境的服务优先调用灰度环境的服务当灰度不存在,则调用生成环境的服务

思路

自定义规则

可从默认的规则ZoneAvoidanceRule入手,因为在生成的时候使用了@ConditionalOnMissingBean说明了可以我们可以自定义Rule

@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;
}
public class ZoneAvoidanceRule extends PredicateBasedRule {

    private static final Random random = new Random();
    
    private CompositePredicate compositePredicate;
    
    public ZoneAvoidanceRule() {
        super();
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this);
        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
    }
    
    private CompositePredicate createCompositePredicate(ZoneAvoidancePredicate p1, AvailabilityPredicate p2) {
        return CompositePredicate.withPredicates(p1, p2)
                             .addFallbackPredicate(p2)
                             .addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
                             .build();
        
    }
    
    
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        ZoneAvoidancePredicate zonePredicate = new ZoneAvoidancePredicate(this, clientConfig);
        AvailabilityPredicate availabilityPredicate = new AvailabilityPredicate(this, clientConfig);
        compositePredicate = createCompositePredicate(zonePredicate, availabilityPredicate);
    }



    /**
     * 被调用的地方是getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
     * chooseRoundRobinAfterFiltering(lb.getAllServers(), key)就是真正要过滤逻辑了
     * */ 
    @Override
    public AbstractServerPredicate getPredicate() {
        return compositePredicate;
    }  

    /**
     * 省略部分代码
     * */  
}

ZoneAvoidanceRule可以得出以下几点

  • 在构造方法中将ZoneAvoidancePredicateAvailabilityPredicate这两个过滤器通过调用createCompositePredicate方法包装成了compositePredicate组合型过滤器,这三个过滤器在上文有详细解释,这里不再赘述
  • createCompositePredicate方法能够将多个过滤器包装进来,然后挨个执行
  • 当执行真正的过滤逻辑时也就是getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key)方法,getPredicate()就是要返回这个包装后的组合型过滤器compositePredicate
  • 由上可知,我们需要定义一个Rule需要继承PredicateBasedRule,并重写上述几个方法

自定义过滤器

规则分析后,接下来要考虑自定义的过滤器要怎么做,从createCompositePredicate方法入手,其中注入了ZoneAvoidancePredicate,我们可以进行分析,关于这个过滤器的作用已在上一篇文章详细的分析,这里只分析关键部分

public class ZoneAvoidancePredicate extends  AbstractServerPredicate {

    /**
     * 省略其余逻辑
     * */
    ZoneAvoidancePredicate(IRule rule) {
        super(rule);
    }
    

    @Override
    public boolean apply(@Nullable PredicateKey input) {
        if (!ENABLED.get()) {
            return true;
        }
        String serverZone = input.getServer().getZone();
        if (serverZone == null) {
            // there is no zone information from the server, we do not want to filter
            // out this server
            return true;
        }
        LoadBalancerStats lbStats = getLBStats();
        if (lbStats == null) {
            // no stats available, do not filter
            return true;
        }
        if (lbStats.getAvailableZones().size() <= 1) {
            // only one zone is available, do not filter
            return true;
        }
        Map<String, ZoneSnapshot> zoneSnapshot = ZoneAvoidanceRule.createSnapshot(lbStats);
        if (!zoneSnapshot.keySet().contains(serverZone)) {
            // The server zone is unknown to the load balancer, do not filter it out 
            return true;
        }
        logger.debug("Zone snapshots: {}", zoneSnapshot);
        Set<String> availableZones = ZoneAvoidanceRule.getAvailableZones(zoneSnapshot, triggeringLoad.get(), triggeringBlackoutPercentage.get());
        logger.debug("Available zones: {}", availableZones);
        if (availableZones != null) {
            return availableZones.contains(input.getServer().getZone());
        } else {
            return false;
        }
    }    
}
  • ZoneAvoidancePredicate继承了AbstractServerPredicate实现了apply方法,此方法是真正执行过滤服务实例的逻辑。
  • 执行有参构造方法,将rule传给了父类

通过以上分析,我们有了思路来做相应的设计

自定义过滤器逻辑

配置

@ConfigurationProperties("spring.cloud.nacos.discovery.metadata")
@Setter
@Getter
public class ExtraRibbonProperties {
    
    private String mark;
}

自动装配配置

@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(RibbonClientConfiguration.class)
@ConditionalOnProperty(value = "ribbon.filter.metadata.enabled", matchIfMissing = true)
@EnableConfigurationProperties(ExtraRibbonProperties.class)
public class ExtraRibbonAutoConfiguration {
    
    @Bean
    public DiscoveryEnabledRule discoveryEnabledRule(ExtraRibbonProperties extraRibbonProperties){
        return new DiscoveryEnabledRule(extraRibbonProperties);
    }
}

自定义规则

public class DiscoveryEnabledRule extends PredicateBasedRule {
    
    /**
     * 这里为静态的原因是ribbon在定时任务执行时是直接调用DiscoveryEnabledRule的构造方法,而不是从spring中获得
     * */
    private static String mark;
    
    private CompositePredicate predicate = null;
    
    public DiscoveryEnabledRule(ExtraRibbonProperties extraRibbonProperties){
        super();
        mark = extraRibbonProperties.getMark();
        MetadataAwarePredicate metadataAwarePredicate = new MetadataAwarePredicate(mark, this);
        Assert.notNull(metadataAwarePredicate, "参数 'abstractServerPredicate' 不能为 null");
        predicate = createCompositePredicate(metadataAwarePredicate, new AvailabilityPredicate(this, null));
    }
    
    public DiscoveryEnabledRule(){
        super();
        MetadataAwarePredicate metadataAwarePredicate = new MetadataAwarePredicate(mark, this);
        Assert.notNull(metadataAwarePredicate, "参数 'abstractServerPredicate' 不能为 null");
        predicate = createCompositePredicate(metadataAwarePredicate, new AvailabilityPredicate(this, null));
    }
    
    @Override
    public AbstractServerPredicate getPredicate() {
        return predicate;
    }
    
    private CompositePredicate createCompositePredicate(AbstractServerPredicate abstractServerPredicate, AvailabilityPredicate availabilityPredicate) {
        return CompositePredicate.withPredicates(abstractServerPredicate, availabilityPredicate)
                .build();
    }
}

自定义过滤器

@Log4j2
public class MetadataAwarePredicate extends AbstractServerPredicate{
    
    public static final String MARK_FLAG_TRUE = "true";
    
    public static final String MARK_FLAG_FALSE = "false";
    
    private static final String MARK_PARAMETER = "mark";
    
    private String mark;
    
    private DiscoveryEnabledRule discoveryEnabledRule;
    
    public MetadataAwarePredicate(String mark,DiscoveryEnabledRule discoveryEnabledRule){
        super(discoveryEnabledRule);
        this.mark = mark;
        this.discoveryEnabledRule = discoveryEnabledRule;
    }
    
    
    @Override
    public boolean apply(PredicateKey input) {
        boolean result = true
        //这里可以写具体的过滤逻辑
        return result;
    }
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。