likes
comments
collection
share

三:Ribbon负载均衡

作者站长头像
站长
· 阅读数 12

1 负载均衡介绍

当前的主流负载均衡方案分为两种:

  • 集中式负载均衡,在客户端和服务提供方中间使用独立的代理方式进行负载,比如硬件F5(直接跟交换机进行连接,任何请求都是先到达交换机,然后由交换机进行集群中的服务提供方选择),或者安装软件Nignx。硬件性能更高,成本高。
  • 客户端根据自己的请求情况做负载均衡,Ribbon属于客户端自己做负载均衡

Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具。Ribbon客户端组件提供了一系列完善的配置,如超时,重试等。通过Load Balancer 获得服务提供的所有机器实例。Ribbon会基于某种规则(轮询,随机)去调用这些服务,也可以实现自己的负载均衡算法。

1.1 客户端的负载均衡

例如Spring cloud Ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法去选择一个服务器,然后进行访问,这是客户端负载均衡。 三:Ribbon负载均衡

1.2 服务端的负载均衡

由Nignx进行负载均衡,先发送请求,然后再通过负载均衡算法,在多个服务器之间选择一个进行访问。

三:Ribbon负载均衡

1.3 常见负载均衡算法
  • 随机, 通过随机选择服务执行,少用
  • 轮询,负载均衡默认实现方式,请求来了之后排队处理
  • 加权轮循,通过对服务器性能的分类,给高配置,低负载的服务器分配更高的权重,均衡各个服务器的压力
  • 地址Hash,通过客户端请求的地址的HASH值取模映射进行服务器调度。ip->HASH
  • 最小连接数,即使请求均衡了,压力也不一定会均衡,最小连接数法就是根据服务器情况,比如请求积压数等参数,将请求分配到当前压力最小的服务器上。最小活跃数。

2 Nacos使用Ribbon

Nacos 2021版本已经没有自带ribbon的整合了,需要引入支持的jar包loadbalancer,且2021版本取消了对ribbon的支持,无法通过修改Ribbon负载均衡的模式来实现nacos提供的负载均衡模式。 参考blog.csdn.net/qq_38050728…

但是老版本的默认使用ribbon(2021之前的版本,这里演示使用的老版本,如下三个依赖版本)。

<spring.cloud.alibaba.version>2.2.9.RELEASE</spring.cloud.alibaba.version>
<spring.boot.version>2.3.12.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR12</spring.cloud.version>

1)首先引入nacos-discovery

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

我们查看nacos-discovery,可见它依赖了Ribbon,因此可以不用在pom文件中引入ribbon依赖。

三:Ribbon负载均衡

2)在spring提供的RestTemplate上添加@LoadBalanced注解,就能自动实现负载均衡

三:Ribbon负载均衡 3)修改controller:在controller中可以直接使用服务命进行调用。

三:Ribbon负载均衡

3 Ribbon负载均衡策略

ribbon中的关键类如下图所示:

三:Ribbon负载均衡

我们通过实现IRule接口可以自定义负载均衡策略,主要的服务选择逻辑方法在choose方法中。(idea中使用ctrl+H快捷键查看IRule的子类)

IClientConfigAware
AbstractLoadBalancerRule
IRule
+ Server choose
+ void setLoadBalancer
+ ILoadBalancer getLoadBalancer
RoundRobbinRule
RandomRule
ClientConfigEnabledRoundRobinRule
RetryRule
NacosRule
ResponseTimeWeightedRule
WeightedResponseTimeRule
PredicateBasedRule
BestAvailableRule
ZoneAvoidanceRule
AvailabilityFilteringRule

基于上述类图,根据每个类名可大概知道每个策略。

  • IRule 所有负载均衡策略的父接口,核心方法choose,用来选择一个服务实例

  • AbstractLoadBalancerRule 抽象类,主要定义了一个ILoadBalancer,用于辅助负责均衡策略选择合适的服务端实例

  • RandomRule 随机选择一个服务实例,再RandomRule的无参构造方法中初始化一个Random对象,然后重写的choose方法调用了choose(ILoadBalancer lb, Object key)这个重载的方法。在重载方法中,每次利用random对象生成一个不大于服务实例总数的随机数,并将该数作为下标以获取一个服务实例。

  • RoundRobbinRelu:轮询负载均衡策略。重写的choose方法中,开启一个计数器count,在while循环中遍历服务清单,获取清单前先通过 incrementAndGetModulo获取一个下标,这个下标是一个不断自增长的数加1然后和服务清单总数取模后获得的,再用下标去服务清单列表中取服务,每次循环计数都会加1,如果连续10次都没有获取到服务,则会警告 log.warn("No up servers available from load balancer: " + lb);

  • RetryRelu:在轮询的基础上进行重试,首先RetryRule中定义了一个subRule,它的实现类就是RoundRobbinRule,然后在RetryRule的choose()方法中,每次还是采用RoundRobinRule中的choose规则来选一个服务实例,如果选到的正常实例正常就返回,如果选择的服务实例为null或者已经失效,则在失效时间deadline之前不断的重试。如果超过了deadline还是没有获取到,则返回一个null。

  • WeightedResponseTimeRule(基于权重的——nacos的NacosRule,Nacos还扩展了一个自己的基于配置的权重扩展),RoundRobinRule的一个子类,进行了功能扩展。根据每个实例的运行情况来计算出实例的权重,然后根据权重进行实例挑选。WeightedResponseTimeRule中有一个名叫DynamicServerWeightTask的定时任务,默认情况下,每隔30秒会计算一次各个服务实例的权重。(计算权重的规则:如果一个服务的平均响应时间越短则权重越大,该实例被选中的概率也就越大

  • ClientConfigEnabledRoundRobinRule:内部定义了RoundRobbinRule.

  • BestAvailableRule: 在CientConfigEnabledRoundRobinRule的基础上主要增加了根据loadBalancerStats中保存的服务实例的状态信息来过滤掉失效的服务实例的功能,顺便找出并发请求最小的服务实例来使用。如果loadBalancerStats为null,则BestAvailableRule将采用父类的服务选择策略(线性轮询)。

  • ZoneAvoidance:(默认规则,复合判断server所在的区域(比如服务器部署在不同的省市区域)的性能和server的可用性选择服务器(如果没有区域的概念,则采用线性轮询))是PredicateBasedRule的一个实现类,只不过多了一个过滤条件,以ZoneAvoidancePredicate为主过滤条件和以AvailabilityPredicate为次过滤条件组成的一个CompositePredicate的组合过滤条件。过滤成功后采用先行轮询(RoundRobinRule)的方式从过滤结果中选择一个出来

  • AvailablilityFilteringRule(先过滤掉故障实例,再选择并发最小的实例)过滤掉一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的后端Server或使用一个AvailabilityPredicate来包含过滤server的逻辑。其实就是检查status记录的各个server的运行状态

3.1 修改默认负载均衡策略

在配置调用其他服务所使用的负载均衡策略时,有两种。全局配置和局部配置。

  • 全局配置:调用其它微服务,一律使用指定的负载均衡策略。即写一个配置类,指定对应的规则。配置类不能放到启动类所在的包下,因为启动类的 ComponentScan在没有指定basePackages时,会将当前类所在的包作为扫描包进行扫描。如果配置类放到启动类包下,会被所有的服务提供方共享。

三:Ribbon负载均衡

三:Ribbon负载均衡

@Configuration
public class RibbonRandomRuleConfig {
    /**
     * 方法名一定要为iRule
     * @return
     */
    @Bean
    public IRule iRule(){
        return new RandomRule();
    }
}
  • 局部配置:调用指定微服务提供的服务时,使用对应的负载均衡算法 修改application.yml

三:Ribbon负载均衡

stock-service:
  ribbon:
  # 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机权重)
      NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
3.2 自定义负载均衡策略

实现接口IRule或者继承基类AbstractLoadBalancerRule,主要的选择服务逻辑在choose方法中。例如写一个随机获取服务的负载均衡策略

public class CustomRule extends AbstractLoadBalancerRule {
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object o) {
        ILoadBalancer lb = this.getLoadBalancer();
        // 获得当前请求的服务的实例
        List<Server> reachableServers = lb.getReachableServers();
        // 线程安全的获取一个随机数
        int random = ThreadLocalRandom.current().nextInt(reachableServers.size());
        Server server = reachableServers.get(random);
        if(server.isAlive()){
            return null;
        }
        return server;
    }
}

然后使用注解或者配置文件进行配置就可以了。

(懒加载)负载均衡器在第一次调用的时候才会进行动态加载,第一次会比较慢,甚至超时。配置的方式使用饥饿加载模式。

三:Ribbon负载均衡

4 使用LoadBalancer替代Ribbon

Spring cloud的LoadBalancer是官方自己提供的客户端均衡负载器,用来代替ribbon 。提供了两种负载均衡的客户端

  • RestTemplate:用于访问Rest服务的客户端,依赖jdk提供的HTTP连接工具。
  • WebClient:从Spring WebFlux5.0版本开始提供的一个非阻塞的基于响应式编程的发送http请求的工具。提供了标准的HTTP的get,post,put,delete等方法。

使用RestTemplate时,如果spring cloud 是老版本(2021之前的),则需要在nacos-discovery中移除Ribbon依赖。

<!--nacos服务发现组件-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <exclusions>
        <exclusion>
        <!--移除ribbon依赖-->
            <groupId>com.cxq.springcloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>

或者直接在application.yml中禁用ribbon.

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        discovery:
          username: nacos
          password: nacos
          # 命名空间用来隔离不同的实例环境
          namespace: public
    loadbalancer:
      ribbon:
        enabled: false

建议直接移除。

而新版本不依赖ribbon,可直接引入loaderbalancer依赖,不用再去禁用。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>2.2.9.RELEASE</version>
</dependency>
转载自:https://juejin.cn/post/7233765235952812088
评论
请登录