实现优先调用统一集群的实例。
案例:为了容灾,我们将内容中心和用户中心都部署在了北京机房和南京机房,为了实现提升性能,我希望实现同机房优先调用,也就是说北京机房的内容中心优先调用北京机房的用户中心实例,如果北京机房找不到任何用户中心的实例,才考虑调用南京机房的实例。为了实现这个目标,我们使用nacos的cluster就非常的方便。不了解nacos的cluster的可以先看一下文章:服务发现(nacos组件)中的nacos服务发现的领域模型。接下来我们代码实现一下:
package com.chuxin.contentcenter.config;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @FileName: NacosSameClusterWeightedRule
* @Description: 实现同一集群优先调用
* @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
* @create: 2019-08-15 16:07
*/
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
/**
* 实现步骤:
* 1.找到指定服务的所有实例
* 2.过滤出相同集群下的所有实例
* 3.如果上述2为空,就用1
* 4.基于权重的负载均衡算法,返回一个实例
*/
@Override
public Server choose(Object key) {
try {
//获取到配置中的集群名称
String clusterName = nacosDiscoveryProperties.getClusterName();
BaseLoadBalancer loadBalancer = (BaseLoadBalancer)this.getLoadBalancer();
//想要请求的微服务的名称
String name = loadBalancer.getName();
//拿到服务发现的相关API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
//1.找到指定服务的所有实例
List<Instance> instances = namingService.selectInstances(name, true);
//2.过滤出相同集群下的所有实例
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> Objects.equals(instance.getClusterName(), clusterName))
.collect(Collectors.toList());
// 3.如果上述2为空,就用1
List<Instance> instancesToBeChosen = new ArrayList<>();
if (CollectionUtils.isEmpty(sameClusterInstances)){
instancesToBeChosen = instances;
log.warn("发生了跨集群的调用,name = {}, clusterName = {}, instances = {}",name,clusterName,instances);
} else {
instancesToBeChosen = sameClusterInstances;
}
//4.基于权重的负载均衡算法,返回一个实例
Instance instance = ExtendsBalancer.getHostByRandomWeightExtends(instancesToBeChosen);
log.info("选择的实例是 instance = {}",instance);
return new NacosServer(instance);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class ExtendsBalancer extends Balancer {
public static Instance getHostByRandomWeightExtends(List<Instance> hosts) {
return getHostByRandomWeight(hosts);
}
}
全局配置类添加的信息
@Bean
public IRule ribbonRule() {
// 使用自定义负载均衡规则(支持nacos设置权重的负载均衡规则,同集群优先调用)
return new NacosSameClusterWeightedRule();
}
配置文件中配置集群名称(每个结点都需要指定):
spring:
cloud:
nacos:
discovery:
# 指定集群名称
cluster-name: BJ
这样就OK了。。。
网友评论