前言
假设有两个微服务一个叫user-center ,一个叫content-center。为了容灾,两个微服务在BJ集群和CD集群都有部署。
且要求同一集群下的应用优先调用,也就是说:content-center如果在BJ集群里那么在调用user-center微服务时优先调用BJ集群下的content-center。 下面来实现。
一、创建一个类NacosSameClusterWeightedRule
这个类要干的事情:
//1.拿到loadBalancer
//2.拿到请求的微服务的名称
//3.用 nacosDiscoveryProperties 拿到服务发现的相关API 以及配置文件中配置的集群名字
//4.用 NocasApi 获取这个微服务的所有实例 A
//5.筛选同集群下的微服务实例集合B
//6.B空用A,否则用B
//7.用Nocas 权重负载均衡
二、代码:
import com.alibaba.nacos.api.exception.NacosException;
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;
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
@Autowired
NacosDiscoveryProperties nacosDiscoveryProperties;
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object o) {
try {
//1.拿到loadBalancer
BaseLoadBalancer loadBalancer = (BaseLoadBalancer)this.getLoadBalancer();
//2.拿到请求的微服务的名称
String name = loadBalancer.getName();
//3.用 nacosDiscoveryProperties 拿到服务发现的相关API 以及配置文件中配置的集群名字
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
String clusterName = nacosDiscoveryProperties.getClusterName();
//4.用 NocasApi 获取这个微服务的所有实例 A
List<Instance> instances = namingService.selectInstances(name, true);
//5.筛选同集群下的微服务实例集合B
List<Instance> sameClusterInstances = instances.stream().filter(instance -> Objects.equals(instance.getClusterName(), clusterName)).collect(Collectors.toList());
//6.B空用A,否则用B
List<Instance> instancesToBeChosen = new ArrayList<>();
if(CollectionUtils.isEmpty(sameClusterInstances)){
log.warn("发生跨集群的调用,instance name:{} clusterName:{}",name,clusterName);
instancesToBeChosen = instances;
}else{
instancesToBeChosen = sameClusterInstances;
}
//7.用NocasApi 权重负载均衡
Instance instance = Balancer_local.getHostByRandomWeight_local(instancesToBeChosen);
log.info("NacosSameClusterWeightedRule.instance:url:{},port:{}",instance.getIp(),instance.getPort());
return new NacosServer(instance);
} catch (NacosException e) {
log.error("NacosSameClusterWeightedRule.NacosException:",e);
e.printStackTrace();
}
return null;
}
}
// 根据 Instance instance = namingService.selectOneHealthyInstance(name);
// 此方法可以根据一个微服务的名字找到其所有节点,然后用权重算法选一个返回。
// 可见这个方法里面一定有一个子方法是:传一个List<Instance> 选节点的方法,我们可以拿来用。
// 源码找到 getHostByRandomWeight(List<Instance> hosts)
// 如果想用源码且不是public的,我们可以自己写个类继承一下,字类就可以调用父类的方法了。
class Balancer_local extends Balancer {
public static Instance getHostByRandomWeight_local(List<Instance> hosts){
return getHostByRandomWeight(hosts);
}
}
注意:spring-cloud-alibaba的版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>