业务场景
应用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()方法中重写自定义的负载策略
在同集群调用负载策略基础上还可以根据权重来进行筛选实例

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

被折叠的 条评论
为什么被折叠?



