扩展ribbon-loadbalanced自定义负载策略(同集群优先原则)

本文介绍了如何扩展Ribbon的负载均衡策略,实现根据客户端集群优先选择同一集群的服务实例。通过自定义负载规则类和配置,确保客户端始终调用与自身相同集群的服务,提高服务调用效率。当同集群服务不可用时,会自动切换到其他集群。

业务场景

应用A调用应用B,应用B下有多个集群,应用A调用应用B时,调用同集群下的应用B实例

项目结构

client为客户端,有两个服务端:应用名都是customize-ribbon-loadbalanced-server,集群分别是beijing和shanghai

client去调用应用customize-ribbon-loadbalanced-server,根据client的集群名来分别调用服务customize-ribbon-loadbalanced-server中相同集群的应用

配置文件

client:application.yml

将client的集群名设置为beijing

server:
  port: 8081
spring:
  application:
    name: customize-ribbon-loadbalanced-client
  cloud:
    nacos:
      discovery:
        server-addr: 10.22.1.102:32063
        cluster-name: beijing

customize-ribbon-loadbalanced-server-beijing:application.yml

将集群名设置为beijing,同时将集群信息配置到元数据中

server:
  port: 8082

spring:
  application:
    name: customize-ribbon-loadbalanced-server

  cloud:
    nacos:
      discovery:
        server-addr: 10.22.1.102:32063
        cluster-name: beijing
        metadata:
          cluster-name: beijing

customize-ribbon-loadbalanced-server-shanghai:application.yml

将集群名设置为shanghai,同时将集群信息配置到元数据中

server:
  port: 8083

spring:
  application:
    name: customize-ribbon-loadbalanced-server

  cloud:
    nacos:
      discovery:
        server-addr: 10.22.1.102:32063
        cluster-name: shanghai
        metadata:
          cluster-name: shanghai

扩展loadbalanced接口

自定义CustomizeClusterPriorityRule类继承AbstractLoadBalancerRule

package cn.sunline.loadbalanced.client.rule;


import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;

public class CustomizeClusterPriorityRule extends AbstractLoadBalancerRule {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }

    @Override
    public Server choose(Object key) {
        //获取当前应用自身集群名
        String clusterName = nacosDiscoveryProperties.getClusterName();
        BaseLoadBalancer loadBalancer = (BaseLoadBalancer)this.getLoadBalancer();

        //获取目标应用的应用名
        String name = loadBalancer.getName();
        NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
        try {
            //根据目标应用名查询目标应用实例集合
            List<Instance> allInstances = namingService.getAllInstances(name);
            logger.info("application:{} current instances counts: {}",name,allInstances.size());
            for (Instance instance : allInstances) {
                if (instance.isHealthy() && instance.isEnabled()) {
                    Map<String, String> metadata = instance.getMetadata();
                    String valueClusterName = metadata.get("cluster-name");
                    logger.info("valueClusterName: {}",valueClusterName);
                    
                    //调用时选择同集群的实例
                    if (valueClusterName.equals(clusterName)) {
                        return new NacosServer(instance);
                    }
                }
            }
        } catch (NacosException e) {
            e.printStackTrace();
        }
        return null;
    }
}

自定义配置负载规则GlobalRibbonConfig

package cn.sunline.loadbalanced.client.configuration;

import cn.sunline.loadbalanced.client.rule.CustomizeClusterPriorityRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GlobalRibbonConfig {

    @Bean
    public IRule getRule() {
        return new CustomizeClusterPriorityRule();
    }

}

自定义配置负载策略CustomeRibbonConfig

package cn.sunline.loadbalanced.client.configuration;

import org.springframework.cloud.netflix.ribbon.RibbonClients;

@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)
public class CustomeRibbonConfig {
}

controller

client controller

package cn.sunline.loadbalanced.client.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ClientController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping
    public String clientRequest() {
        String forObject = restTemplate.getForObject("http://customize-ribbon-loadbalanced-server/test", String.class);
        return forObject;
    }
}

customize-ribbon-loadbalanced-server-beijing

package cn.sunline.loadbalanced.server.beijing.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServerController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @GetMapping("test")
    public String test() {
        logger.info("beijing-test");
        return "beijing-test";
    }
}

customize-ribbon-loadbalanced-server-shanghai

package cn.sunline.loadbalanced.server.shanghai.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServerController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @GetMapping("test")
    public String test() {
        logger.info("shanghai-test");
        return "beijing-test";
    }
}

测试

启动client和两个server应用;

调用client controller:根据同集群调用选择,应该会请求到集群为beijing的实例上

可以看到不管请求多少次,请求都会发送到集群名为beijing的服务上

如果说把集群为beijing的服务停止运行或者说修改集群为其他名字之后重启,再次发送client请求会出现:

可见:client没有发现应用名customize-ribbon-loadbalanced-server且集群为beijing的服务

总结

扩展ribbon-loadbalanced自定义负载均衡策略接口只需要继承AbstractLoadBalancerRule即可;然后在choose()方法中重写自定义的负载策略

在同集群调用负载策略基础上还可以根据权重来进行筛选实例

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值