专注app软件定制开发SpringCloud(10) 自定义负载均衡策略

一、前言

专注app软件定制开发本文将自定义策略来实现权限策略专注app软件定制开发同一集群优先使用带版本策略,专注app软件定制开发主要解决在本地开发环专注app软件定制开发境启动相同服务时,调用服务会跑到其他人那里。

简要逻辑:在通过注册服务时,添加version参数绑定本地服务ip信息,在服务调用时,去获取nacos上注册服务信息,通过version参数条件去指定调用具体服务。

ex: 服务A调用服务B
如果服务B的参数值和服务A的version参数值一致,即会优先调用与服务A相同version值的服务B
如果没有与服务A相同version值的服务B,再去随机按权重调用服务B

环境:

  1. spring-boot-dependencies 2.3.2.RELEASE
  2. spring-cloud-dependencies Hoxton.SR8
  3. spring-cloud-alibaba-dependencies 2.2.3.RELEASE

二、自定义负载均衡策略

1、自定义负载均衡策略-权重

@Slf4jpublic class BalancerWeightRule extends AbstractLoadBalancerRule {    @Autowired    private NacosServiceManager nacosServiceManager;    @Autowired    private NacosDiscoveryProperties nacosDiscoveryProperties;    @Override    public void initWithNiwsConfig(IClientConfig iClientConfig) {        // 读取配置文件, 并且初始化, ribbon内部基本上用不上    }    /**     * 这个方法是实现负载均衡策略的方法     */    @Override    public Server choose(Object key) {        try {            // 1、获取当前服务的分组名称            String groupName = this.nacosDiscoveryProperties.getGroup();            // 2、获取当前服务的负载均衡器            BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer();            // 3、获取目标服务的服务名            String serviceName = baseLoadBalancer.getName();            // 4、获取nacos提供的服务注册api            NamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());            // 5、根据目标服务名称和分组名称去获取服务实例,nacos实现了权重的负载均衡算法  false: 及时获取nacos注册服务信息            Instance toBeChooseInstance = namingService.selectOneHealthyInstance(serviceName, groupName, false);            BalancerInstanceUtil.printInstance(BalancerRuleTypeEnum.WEIGHT, toBeChooseInstance);            return new NacosServer(toBeChooseInstance);        } catch (NacosException e) {            log.error("自定义负载均衡策略-权重 调用异常: ", e);            return null;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

2、自定义负载均衡策略-同一集群优先使用带版本实例

@Slf4jpublic class BalancerVersionRule extends AbstractLoadBalancerRule {    @Autowired    private NacosServiceManager nacosServiceManager;    @Autowired    private NacosDiscoveryProperties nacosDiscoveryProperties;    @Override    public void initWithNiwsConfig(IClientConfig iClientConfig) {    }    @Override    public Server choose(Object o) {        try {            // 1、获取当前服务的分组名称、集群名称、版本号            String groupName = this.nacosDiscoveryProperties.getGroup();            String clusterName = this.nacosDiscoveryProperties.getClusterName();            String version = this.nacosDiscoveryProperties.getMetadata().get("version");            // 2、获取当前服务的负载均衡器            BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer();            // 3、获取目标服务的服务名            String serviceName = baseLoadBalancer.getName();            // 4、获取nacos提供的服务注册api            NamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());            // 5、获取所有服务名为serviceName的服务实例   false: 及时获取nacos注册服务信息            List<Instance> allInstanceList = namingService.getAllInstances(serviceName, groupName, false);            // 6、过滤有相同集群的服务实例            List<Instance> sameClusterInstanceList = Lists.newLinkedList();            for (Instance instance : allInstanceList) {                if (instance.getClusterName().equals(clusterName)) {                    sameClusterInstanceList.add(instance);                }            }            // 7、过滤相同版本的服务实例            List<Instance> sameVersionInstanceList = Lists.newLinkedList();            for (Instance instance : sameClusterInstanceList) {                if (version.equals(instance.getMetadata().get("version"))) {                    sameVersionInstanceList.add(instance);                }            }            // 8、选择合适的服务实例            Instance toBeChooseInstance;            if (CollectionUtils.isEmpty(sameVersionInstanceList)) {                toBeChooseInstance = WeightedBalancer.chooseInstanceByRandomWeight(sameClusterInstanceList);                BalancerInstanceUtil.printInstance(BalancerRuleTypeEnum.VERSION_WEIGHT, toBeChooseInstance);            } else {                toBeChooseInstance = WeightedBalancer.chooseInstanceByRandomWeight(sameVersionInstanceList);                BalancerInstanceUtil.printInstance(BalancerRuleTypeEnum.VERSION, toBeChooseInstance);            }            return new NacosServer(toBeChooseInstance);        } catch (NacosException e) {            log.error("Nacos同一集群带版本优先调用异常: ", e);            return null;        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

版本策略所需随机权重类

public class WeightedBalancer extends Balancer {    public static Instance chooseInstanceByRandomWeight(List<Instance> instanceList) {        // 这是父类Balancer自带的根据随机权重获取服务的方法.        return getHostByRandomWeight(instanceList);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3、启用自定义负载均衡策略

可参考

@Configuration@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)public class CustomRibbonConfig {}
  • 1
  • 2
  • 3
  • 4
  • 5
@Slf4j@Data@Configurationpublic class GlobalRibbonConfig {    @Value("${ribbon.rule-type:}")    private String ruleType;    @Bean    public IRule getRule() {        // 自定义负载均衡策略        BalancerRuleTypeEnum balancerRuleTypeEnum = BalancerRuleTypeEnum.getEnum(this.ruleType);        log.info("使用自定义负载均衡策略:[{}]", balancerRuleTypeEnum.getDesc());        switch (balancerRuleTypeEnum) {            case WEIGHT:                // 权重                return new BalancerWeightRule();            case VERSION:                // 同一集群优先带版本实例                return new BalancerVersionRule();            default:                // 默认权重                return new BalancerWeightRule();        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

通过配置ribbon.rule-type参数值来选择使用哪一种负载均衡策略

ribbon:  rule-type: version
  • 1
  • 2

4、负载均衡策略枚举类和工具类

@Slf4j@Getter@AllArgsConstructorpublic enum BalancerRuleTypeEnum {    /**     * 权重     */    WEIGHT("weight", "权重"),    /**     * 同一集群使用相同版本     */    VERSION("version", "同一集群使用相同版本"),    /**     * 同一集群无相同版本,使用权重     */    VERSION_WEIGHT("version_weight", "同一集群无相同版本,使用权重");    /**     * 规则类型     */    private final String type;    /**     * 规则描述     */    private final String desc;    private static final List<BalancerRuleTypeEnum> LIST = Lists.newArrayList();    static {        LIST.addAll(Arrays.asList(BalancerRuleTypeEnum.values()));    }    /**     * 根据指定的规则类型查找相应枚举类     *     * @param type 规则类型     * @return 规则类型枚举信息     * @author zhengqingya     * @date 2020/9/13 18:46     */    public static BalancerRuleTypeEnum getEnum(String type) {        for (BalancerRuleTypeEnum itemEnum : LIST) {            if (itemEnum.getType().equals(type)) {                return itemEnum;            }        }        log.warn("未找到指定的负载均衡策略,默认权重策略!");        return WEIGHT;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
@Slf4jpublic class BalancerInstanceUtil {    public static void printInstance(BalancerRuleTypeEnum ruleTypeEnum, Instance instance) {        if (instance == null) {            return;        }        log.info("自定义负载均衡策略-[{}] serviceName: [{}], clusterName: [{}], ip: [{}] port: [{}]",                ruleTypeEnum.getDesc(),                instance.getServiceName(),                instance.getClusterName(),                instance.getIp(),                instance.getPort()        );    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

三、配置ribbon饥饿加载模式

主要解决:在服务启动后,第1次访问可能会报错
产生原因:ribbon服务调用默认使用懒加载模式,即在调用的时候才会去创建相应的client

ribbon:  # 配置饥饿加载模式  eager-load:    # 开启饥饿加载模式    enabled: true    # 指定需要饥饿加载的服务名    clients:      - "demo"      - "system"      - "tool"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

四、本文案例demo源码


今日分享语句:
我不敢休息,因为我没有存款。我不敢说累,因为我没有成就。我不敢偷懒,因为我还要生活。我能放弃选择,但是我不能选择放弃。坚强拼搏是我唯一的选择。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发