Spring Cloud Aliaba - Ribbon

Ribbon(有关介绍见RestTemplate末尾)

Ribbon负载均衡实现策略

Ribbon负载均衡实现策略通过接口IRule进行实现,默认使用ZoneAvoidanceRule规则进行负载均衡。

image-20210724140812265

实现自定义负载均衡算法:

使用@Configuration注解进行配置

@Configuration
public class RibbonConfig {
    @LoadBalanced //如果使用了loadBalancerClient进行了代理,则已经做过一次负载均衡,此处的注解不能加
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

可以将主启动类中的RestTemplate配置转入到此类中。在此类中可以通过@Bean 创建IRule的实例来实现替换负载均衡的规则:

image-20210724141532030

编写规则类的时候需要继承AbstractLoadBalancerRule ,最上层还是实现IRule接口,但是如果直接实现IRule接口的话,需要实现其中的三个方法,比较繁琐,并不推荐:

image-20210724142411445

如果继承AbstractLoadBalancerRule类的话还是实现了IRule接口,但是对于setLoadBalancer方法和getLoadBalancer方法在其中已经默认实现了,不需要我们再去进行实现:

image-20210724142559120

继承抽象方法的负载均衡算法是需要实现两个方法:

image-20210724142739918

initWithNiwsConfig中基本不需要实现,这个方法是初始化一些配置信息。我们将方法编写在choose方法中。

我们也可以通过配置文件远程指定负载均衡策略:

image-20210724144543436

image-20210724144228103

前面添加的是服务提供者的名字,后面指定负载均衡算法的位置即可。

官方提供了很多种已经实现好的负载均衡算法可供选择:

image-20210724144355315


Ribbon的组成

image-20210724144646531

image-20210724144722763

image-20210724145258646

远程配置扩展接口:

image-20210724145638929

image-20210724145707254


Nacos实现权重负载均衡

启动两台以上的服务提供者,客户端的负载均衡算法必须为NacosRule负载均衡算法

打开Nacos服务面板,点击服务管理-服务列表找到对应的服务:

image-20210724150421751

点击详情进入配置面板:

image-20210724150512961

通过点击编辑按钮,配置每一个服务的权重值:

image-20210724150544775


Nacos实现优先调用同集群服务功能

客户端调用服务时,如果有两个同样的服务一个在同集群,一个在另外的集群中,会优先调用与客户端在同集群中的服务。只有当同集群的集群宕机了,才会从另外的集群中调用服务,在客户端中同时也会出现调用其他集群的警告信息。应用场景:异地容灾

实现方式:需要在客户端和服务端的配置文件中增加配置:

image-20210724151450807

后面添加所指向的集群名称。


实现基于版本的负载均衡策略

客户端指定调用版本的服务,在配置文件中指定版本号。服务端在配置文件中配置版本号。符合客户端中的版本的服务,才会被调用。

服务端配置:

image-20210724151735813

客户端配置:

spring.cloud.discoery.metadata.version=v2

实现策略:

public class MyRuleRibbon extends AbstractLoadBalancerRule {

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    //Logger是Log4j包里面的类 主要用来书写日志文件 和输出相关报错信息 并将报错或异常信息输出到控制台或日志文件 private修饰符 将产生的Logger对象私有化 static修饰符表示静态的 总之只有一个对象产生
    private static final Logger log = LoggerFactory.getLogger(MyRuleRibbon.class);

    public void initWithNiwsConfig(IClientConfig iClientConfig) {
        //初始化一些配置信息,不需要我们实现
    }

    public Server choose(Object key) {
        System.out.println("正在使用MyRuleRibbon基于版本号的负载均衡算法");
        //负载均衡规则:优先选择同集群下,符合metadata的实例
        //如果没有,就选择所有集群下,符合metadata的实例
        //===================================================
        //1.查询所有实例A
        //2.筛选元数据匹配的实例B
        //3.筛选出同cluster下元数据匹配的实例C
        //4.弱国C为空,就用B
        //5.随机选择实例
        //===================================================
        try{
            String clusterName = this.nacosDiscoveryProperties.getClusterName();
            final String targetVersion = this.nacosDiscoveryProperties.getMetadata().get("version");

            DynamicServerListLoadBalancer listLoadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String name = listLoadBalancer.getName();

            NamingService namingService = this.nacosDiscoveryProperties.namingServiceInstance();

            //所有实例
            List<Instance> instances = namingService.selectInstances(name,true);

            List<Instance> metadataMatchInstances = instances;

            //如果配置了版本映射,那么只调用元数据匹配的实例
            if (StringUtils.isNotBlank(targetVersion)){
                metadataMatchInstances = instances.stream()
                        .filter(instance-> Objects.equals(targetVersion,instance.getMetadata().get("version")))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(metadataMatchInstances)){
                    log.warn("未找到元数据匹配的目标服务实例,请检查配置:targetVersion = {},instance = {}",targetVersion,instances);
                    return null;
                }
            }
            List<Instance> clusterMetadataMatchInstances = metadataMatchInstances;
            //如果配置了集群的名称,需要筛选同集群下元数据匹配的实例
            if (StringUtils.isNotBlank(clusterName))
            {
                clusterMetadataMatchInstances = metadataMatchInstances.stream()
                        .filter(instance -> Objects.equals(clusterName,instance.getClusterName()))
                        .collect(Collectors.toList());
                if (CollectionUtils.isEmpty(clusterMetadataMatchInstances)){
                    clusterMetadataMatchInstances = metadataMatchInstances;
                    log.warn("发生跨集群调用,clusterName = {},targetVersion = {}, clusterMetadataMatchInstance={}",clusterName,targetVersion,clusterMetadataMatchInstances);
                }
            }
            Instance instance = ExtendBalancer.getHostByRandomWeight2(clusterMetadataMatchInstances);
            return new NacosServer(instance);
        } catch (Exception e) {
            log.warn("发生异常",e);
            return null;
        }
        
    }
}

Nacos不可以跨命名空间调用

服务可以指定命名空间:

image-20210724155032555

dev 可以替换为命名空间的id来指定一个唯一的命名空间

posted @ 2021-08-11 18:11  会编程的老六  阅读(73)  评论(0编辑  收藏  举报