分享

Ribbon负载均衡

 码农9527 2021-10-20

SpringCloudRibbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于NetflixRibbon实现。通过SpringCloud封装,可以轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用,作为一个工具类,Ribbon不需要独立部署。

Ribbon负载均衡

根据负载均衡示意图开始创建Ribbon负载均衡项目。

创建provider1、2、3

复制eureka-provider-8081,重命名为ribbon-provider-8201并配置成maven项目。

在application.yml文件中修改端口号。

server:
  port: 820112复制代码类型:[java]

为了方便运行时识别对应的provider,在PetsServiceImpl.java中改写查询部分——name+端口号。

依照上面的过程配置ribbon-provider-8202,ribbon-provider-8203。

启动项目,在postman中查看查询结果。

在这里,默认的顺序是1、3、2。从这个结果可以看出负载均衡默认是轮询的。这种轮询的状态是可以修改的。

Ribbon默认提供的负载均衡策略

Ribbon的内置负载均衡策略一共有7种。

RoundRobinRule(默认)

轮询策略,默认采用的策略。经过一轮轮询没有找到可用的provider,最多重复10轮,如果还没有找到则返回null。

RandomRule

随机策略,从多个备选provider种,随机选择一个。

RetryRule

重试策略,先根据默认策略进行轮询,获取失败后,在一个默认时间后进行重试。默认时长为500ms。

AvailabilityFilteringRule

可用过滤算法,过滤掉那些不可用的provider(熔断、连接极限、连接失败),对剩余的provider进行轮询。

ZoneAvoidanceRule

zone回避策略,使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个provider,根据provider所在zone及provider的可用性,对provider进行选择。

WeightedResponseTimeRule

权重响应时间策略,根据响应时间分配一个权重,响应时间越长,权重越小,被选中的可能性越低。

更换内置负载均衡策略

通过修改配置文件或JavaConfig类达到更换内置负载均衡策略的目的。

复制feign-consumer-8080,重命名为ribbon-consumer-8080并配置为maven文件。

修改配置文件

# 修改负载均衡策略
# 提供者的微服务名称
familycloud-provider-depart:
  # 指定要使用的负载均衡策略
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule123456复制代码类型:[java]

启动项目,在postman种进行测试,得到的结果是随机的。

配置JavaConfig类

改写PetsConfigure.java

@Configuration
public class PetsConfigure {
    // 指定Ribbon使用随机算法策略
    @Bean
    public IRule RibbonBalanceRule(){
        return new RandomRule();
    }
}12345678复制代码类型:[java]

启动项目,在postman种进行测试,得到的结果跟更换内置负载均衡策略结果都为随机。

自定义负载均衡策略

Ribbon可以自定义负载均衡策略,负载均衡算法类需要实现IRule接口。

要实现的是从所有可用的provider中排除掉指定端口号的provider,剩

余provider进行随机选择。

定义CRule类

在获取排除了指定端口的所有剩余Servers的部分可以使用普通代码方式实现也可以使用Lambda方式实现。

普通代码方式实现

package com.javafamily.balance;

import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 从所有可用的provider中排除掉指定端口号的provider,剩余provider进行随机选择。
 */
public class CRule implements IRule {

    private ILoadBalancer lb;
    // 记录所有要排除的端口号
    private List<Integer> excludePorts;

    public CRule() {
    }

    public CRule(List<Integer> excludePorts) {
        this.excludePorts = excludePorts;
    }

    @Override
    public Server choose(Object key) {

        // 获取所有UP状态的server
        List<Server> servers = lb.getReachableServers();
        // 获取到排除了指定端口的所有剩余Servers
        List<Server> availableServers = getAvailableServers(servers);
        // 对剩余的Servers通过随机方式获取一个Server
        return getAvailableRandomServer(availableServers);
    }

    // 获取到排除了指定端口的所有剩余Servers
    // 使用普通代码方式实现
    private List<Server> getAvailableServers(List<Server> servers) {
        // 若没有指定要排除的port,则直接返回所有Server
        if (excludePorts == null || excludePorts.size() == 0) {
            return servers;
        }

        // 用于存放真正可用的Server
        List<Server> aservers = new ArrayList<>();
        for (Server server : servers) {
            boolean isExclude = false;
            // 将当前遍历Server的端口号与要排除的端口号进行对比
            for (Integer port : excludePorts) {
                if (server.getPort() == port) {
                    isExclude = true;
                    break;
                }
            }
            if (!isExclude) {
                aservers.add(server);
            }
        }
        return aservers;
    }

    // 对剩余的Servers通过随机方式获取一个Server
    private Server getAvailableRandomServer(List<Server> servers) {
        // 获取一个[0,servers.size())的随机整数
        int index = new Random().nextInt(servers.size());
        return servers.get(index);
    }

    @Override
    public void setLoadBalancer(ILoadBalancer lb) {
        this.lb = lb;
    }

    @Override
    public ILoadBalancer getLoadBalancer() {
        return lb;
    }
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081复制代码类型:[java]

Lambda方式实现

package com.javafamily.balance;

import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;

import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * 从所有可用的provider中排除掉指定端口号的provider,剩余provider进行随机选择。
 */
public class CRule implements IRule {

    private ILoadBalancer lb;
    // 记录所有要排除的端口号
    private List<Integer> excludePorts;

    public CRule() {
    }

    public CRule(List<Integer> excludePorts) {
        this.excludePorts = excludePorts;
    }

    @Override
    public Server choose(Object key) {

        // 获取所有UP状态的server
        List<Server> servers = lb.getReachableServers();
        // 获取到排除了指定端口的所有剩余Servers
        List<Server> availableServers = getAvailableServers(servers);
        // 对剩余的Servers通过随机方式获取一个Server
        return getAvailableRandomServer(availableServers);
    }

    // 获取到排除了指定端口的所有剩余Servers
    // 使用Lambda方式实现
    private List<Server> getAvailableServers(List<Server> servers) {
        // 若没有指定要排除的port,则直接返回所有Server
        if (excludePorts == null || excludePorts.size() == 0) {
            return servers;
        }

        // 用于存放真正可用的Server
        List<Server> aservers = servers.stream()  // 将list变为stream
                // filter():只要是能使filter()参数结果为true的元素就能通过过滤
                // noneMatch():用于判断stream中的元素是否全部都不符合。只要找到一个符合的元素该方法就返回false
                .filter(server -> excludePorts.stream().noneMatch(port -> server.getPort() == port))
                // 将最终的stream变为list
                .collect(Collectors.toList());

        return aservers;
    }

    // 对剩余的Servers通过随机方式获取一个Server
    private Server getAvailableRandomServer(List<Server> servers) {
        // 获取一个[0,servers.size())的随机整数
        int index = new Random().nextInt(servers.size());
        return servers.get(index);
    }

    @Override
    public void setLoadBalancer(ILoadBalancer lb) {
        this.lb = lb;
    }

    @Override
    public ILoadBalancer getLoadBalancer() {
        return lb;
    }
}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273复制代码类型:[java]

配置JavaConfig类

// 修改负载均衡策略为:自定义策略
@Bean
public IRule loadBalanceRule() {
    List<Integer> excludePorts = new ArrayList<>();
    // 只对8201、8202进行随机
    excludePorts.add(8203);
    return new CRule(excludePorts);
}12345678复制代码类型:[java]

重新启动项目,在postman中进行测试,得到只有8201、8202没有8203进行随机的结果。

gitee

https:///javainfamily/spring-cloud

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多