SpringCloudAlibaba - 扩展 Ribbon 同集群优先调用
前言
记录下Ribbon
优先调用同一集群下实例的实现
环境
Spring Cloud Hoxton.SR9 + Spring Cloud Alibaba 2.2.6.RELEASE + Nacos 1.4.2
测试用例
测试内容
实现内容中心调用用户中心时优先调用同一集群下实例
用户中心 user-center
TestController.java
@RestController
@Slf4j
public class TestController {
@GetMapping("/test/{name}")
public String test(@PathVariable String name) {
log.info("请求...");
return "hello " + name;
}
}
内容中心 content-center
TestController.java
@GetMapping("test3")
public String test3() {
return restTemplate.getForObject(
"http://user-center/test/{name}",
String.class,
"Coisini"
);
}
具体实现
代码配置
- 服务消费者(内容中心)配置如下:
NacosSameClusterWeightedRule.java
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
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.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Description Ribbon-同一集群优先调用
*/
@Slf4j
public class NacosSameClusterWeightedRule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;
/**
* 读取配置文件,并初始化 NacosWeightedRule
* @param iClientConfig
*/
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
/**
* 同一集群优先调用
* @param o
* @return
*/
@Override
public Server choose(Object o) {
try {
// 拿到配置文件中的集群名称 kunming
String clusterName = nacosDiscoveryProperties.getClusterName();
BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
// 想要请求的微服务的名称
String name = loadBalancer.getName();
// 拿到服务发现的相关API
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// 1. 找到指定服务的所有实例 A
List<Instance> instances = namingService.selectInstances(name, true);
// 2. 过滤出相同集群下的所有实例 B
List<Instance> sameClusterInstances = instances.stream()
.filter(instance -> Objects.equals(instance.getClusterName(), clusterName))
.collect(Collectors.toList());
// 3. 如果B是空,就用A
List<Instance> instancesToBeChosen = new ArrayList<>();
if (CollectionUtils.isEmpty(sameClusterInstances)) {
instancesToBeChosen = instances;
log.warn("发生跨集群的调用, name = {}, clusterName = {}, instances = {}",
name,
clusterName,
instances
);
} else {
instancesToBeChosen = sameClusterInstances;
}
// 4. 基于权重的负载均衡算法,返回1个实例
Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToBeChosen);
log.info("选择的实例是 port = {}, instance = {}", instance.getPort(), instance);
return new NacosServer(instance);
} catch (NacosException e) {
log.error("Nacos同一集群优先调用异常", e);
return null;
}
}
}
RibbonConfiguration.java
import com.coisini.contentcenter.configuration.NacosSameClusterWeightedRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description Ribbon配置类
*/
@Configuration
public class RibbonConfiguration {
/**
* 自定义负载均衡规则
* NacosSameClusterWeightedRule 同集群优先调用
* @return
*/
@Bean
public IRule ribbonRule() {
return new NacosSameClusterWeightedRule();
}
}
UserCenterRibbonConfiguration.java
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;
import ribbonconfiguration.RibbonConfiguration;
/**
* @Description 用户中心配置类
*/
@Configuration
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class UserCenterRibbonConfiguration {
}
content-center -> application.yml
,内容中心配置集群为kunming
spring:
application:
# 服务名称
name: content-center
cloud:
nacos:
discovery:
# 指定nacos server的地址
server-addr: localhost:8848
# 集群名称 kunming
cluster-name: kunming
测试
user-center -> application.yml
,启动用户中心双实例,集群-端口分别为yuxi-8081
,kunming-8082
# 8081 端口 实例1
spring:
application:
# 服务名称
name: user-center
cloud:
nacos:
discovery:
# 指定nacos server的地址
server-addr: localhost:8848
# 指定集群名称
cluster-name: yuxi
# 8082 端口 实例2
spring:
application:
# 服务名称
name: user-center
cloud:
nacos:
discovery:
# 指定nacos server的地址
server-addr: localhost:8848
# 指定集群名称
cluster-name: kunming
- 启动效果如下所示,因内容中心与用户中心(
8082
)属于同一集群kunming
,发生调用时会优先选择8082
端口的用户中心
- 访问测试接口
http://localhost:8010/test3
- 关闭用户中心(
8082
)实例再次访问
...至此,已实现Ribbon
的同集群优先调用
项目源码
GitHub
: https://github.com/Maggieq8324/coisini-cloud-alibabaGitee
: https://gitee.com/maggieq8324/coisini-cloud-alibaba