Ribbon的负载均衡策略

一、Ribbon负载均衡

如上图所示,负载均衡就是避免单个服务的实例处理大批量请求而导致其他实例空闲,造成资源浪费。负载均衡分为客户端、服务端的负载均衡,它们最大的区别在于维护服务器的清单保存的位置不同,如:Ribbon属于客户端负载均衡,客户端根据注册中心的服务实例的状态,判定是否访问某个实例。那么判定访问哪个实例,就是负载均衡策略要做的事。Ribbon的负载均衡有三个主要接口:com.netflix.loadbalancer.IPing(服务的检测)、com.netflix.loadbalancer.IRule(定义均衡策略)、com.netflix.loadbalancer.ILoadBalancer(根据IRule请求实例)

二、Ribbon的负载均衡策略

如上图所示,是IRule的类图。如果需要自定义均衡策略,则继承com.netflix.loadbalancer.AbstractLoadBalancerRule抽象类。如下图所示是Ribbon的7种均衡策略。默认是com.netflix.loadbalancer.ZoneAvoidanceRule(综合判定来选择服务实例)。

三、自定义负载均衡策略

注意:自定义均衡策略,则继承com.netflix.loadbalancer.AbstractLoadBalancerRule抽象类。覆写代码参考该抽象类的实现类。如下代码所示。核心代码是chooseIndex(int reachableCount)方法。

package com.common.instance.gateway.config.ribbon;

import com.log.util.LogUtil;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.springframework.context.annotation.Configuration;

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

/**
 * @description 自定义Ribbon负载均衡策略
 * @author TCM
 * @version 1.0
 * @date 2021/4/1 10:58
 **/
@Configuration
public class MyRibbonBalancerRule extends AbstractLoadBalancerRule {

    // 所有服务实例
    private volatile int total;
    // 实例的索引
    private volatile int index;
    // 可用的所有实例
    List<Server> upList = new ArrayList<>();

    public Server choose(ILoadBalancer lb, Object key) {
        LogUtil.info(String.format("lb=%s,key=%s", lb, key.toString()));
        // 负载均衡器是否为null
        if (lb == null) {
            return null;
        }

        Server server = null;

        while (server == null) {
            // 当前线程是否已中断
            if (Thread.interrupted()) {
                return null;
            }

            // 获取负载均衡器中的所有服务实例
            List<Server> allList = lb.getAllServers();
            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }

            if (total == 0) {
                // 可用的所有实例
                upList = lb.getReachableServers();
            }

            // 修改当前索引
            chooseIndex(lb.getReachableServers().size());
            // 根据索引获取服务
            server = upList.get(index);

            if (server == null) {
                Thread.yield();
                continue;
            }
            if (server.isAlive()) {
                return (server);
            }
            server = null;
            Thread.yield();
        }

        return server;

    }

    // 修改当前索引
    protected void chooseIndex(int reachableCount) {
        if (total < 3) {
            if (upList.size() != reachableCount) {
                index = 0;
            }
            total ++;
        } else {
            total = 0;
            index ++;
            if (index >= reachableCount) {
                index = 0;
            }
        }
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }


}

gateway的yml配置内容:ribbon.NFLoadBalancerRuleClassName: com.common.instance.gateway.config.ribbon.MyRibbonBalancerRule

# hystrix开启
feign:
  hystrix:
    enabled: true
hystrix:
  command:
    default:  # default全局有效,service id指定应用有效
      execution:
        timeout:
          # true则超时根据熔断超时,false则ribbon控制
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 4000 # 断路器超时时间,默认1000ms
# ribbon配置
ribbon:
  OkToRetryOnAllOperations: true # 所有请求重试,默认false
  ReadTimeout: 3000               # 负载均衡超时时间,默认值5000ms
  ConnectTimeout: 1000            # 请求连接的超时时间,默认值2000ms
  MaxAutoRetries: 0               # 当前实例的重试次数,默认0
  MaxAutoRetriesNextServer: 2     # 切换实例的重试次数,默认1
  NFLoadBalancerRuleClassName: com.common.instance.gateway.config.ribbon.MyRibbonBalancerRule

spring:
  cloud:
    gateway:
      # gateway发现该eureka下的所有服务
      discovery:
        locator:
          enabled: false
          lowerCaseServiceId: true
      default-filters:
        - name: Hystrix
          args:
            name: default
            fallbackUri: 'forward:/fallback/global'
      routes:
        - id: ${application.name.instance-demo}
          predicates:
            - Path=/${application.name.instance-demo}/**
          uri: lb://${application.name.instance-demo}

gateway路由接口代码:

package com.common.instance.demo.controller;

import com.common.instance.demo.core.Response;
import com.common.instance.demo.service.RibbonService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @description ribbon负载均衡策略
 * @author TCM
 * @version 1.0
 * @date 2021/3/29 20:30
 **/
@RestController
@RequestMapping("/ribbon")
@Api(tags = "Ribbon测试")
public class RibbonController {

    @Resource
    private RibbonService ribbonService;

    @GetMapping("/rule")
    @ApiOperation("Ribbon策略")
    public Response<String> testRibbonRule(int mills) {
        try {
            Thread.sleep(mills);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String result = ribbonService.testRibbonRule();
        return Response.success(result);
    }

}
package com.common.instance.demo.service.impl;

import com.common.instance.demo.service.RibbonService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * @author TCM
 * @version 1.0
 * @description TODO
 * @date 2021/3/29 20:41
 **/
@Service
public class RibbonServiceImpl implements RibbonService {

    @Value("${spring.cloud.client.ip-address}")
    private String ipAddress;

    @Value("${server.port}")
    private String port;

    @Override
    public String testRibbonRule() {
        return String.format("Ribbon均衡策略测试:主机%s:%s", ipAddress, port);
    }
}

测试结果:

连续3次:发生熔断

{
    "success": false,
    "code": "500",
    "message": "网络发生异常,请稍后重试!",
    "tip": "操作失败",
    "data": null
}

连续3次:9012端口

{
    "success": true,
    "code": "200",
    "message": "操作成功",
    "tip": "操作成功",
    "data": "Ribbon均衡策略测试:主机192.168.1.107:9012"
}

连续3次:9013端口

{
    "success": true,
    "code": "200",
    "message": "操作成功",
    "tip": "操作成功",
    "data": "Ribbon均衡策略测试:主机192.168.1.107:9013"
}

 

  • 0
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值