当前位置:网站首页>扩展Ribbon支持Nacos权重的三种方式
扩展Ribbon支持Nacos权重的三种方式
2022-06-22 19:25:00 【菜鸟是大神】
Nacos支持权重配置,这是个比较实用的功能,例如:
- 把性能差的机器权重设低,性能好的机器权重设高,让请求优先打到性能高的机器上去;
- 某个实例出现异常时,把权重设低,排查问题,问题排查完再把权重恢复;
- 想要下线某个实例时,可先将该实例的权重设为0,这样流量就不会打到该实例上了——此时再去关停该实例,这样就能实现优雅下线啦。当然这是为Nacos量身定制的优雅下线方案——Spring Cloud中,要想实现优雅下线还有很多姿势,详见:《实用技巧:Spring Cloud中,如何优雅下线微服务?》 ,里面笔者总结了四种优雅下线的方式。
然而测试发现,Nacos权重配置对Spring Cloud Alibaba无效。也就是说,不管在Nacos控制台上如何配置,调用时都不管权重设置的。
Spring Cloud Alibaba通过整合Ribbon的方式,实现了负载均衡。所使用的负载均衡规则是 ZoneAvoidanceRule 。
本节来探讨如何扩展Ribbon,让其支持Nacos的权重配置,笔者总结了三种方案。
方案1:自己实现负载均衡规则
思路:
自己首先一个Ribbon负载均衡规则就可以了。
- 权重配置啥的,都可以在实例信息中获取到。
- 自己基于权重配置,计算出一个实例即可。
代码:
@Slf4j
public class NacosWeightRandomV1Rule extends AbstractLoadBalancerRule {
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
@Override
public Server choose(Object key) {
List<Server> servers = this.getLoadBalancer().getReachableServers();
List<InstanceWithWeight> instanceWithWeights = servers.stream()
.map(server -> {
// 注册中心只用Nacos,没同时用其他注册中心(例如Eureka),理论上不会实现
if (!(server instanceof NacosServer)) {
log.error("参数非法,server = {}", server);
throw new IllegalArgumentException("参数非法,不是NacosServer实例!");
}
NacosServer nacosServer = (NacosServer) server;
Instance instance = nacosServer.getInstance();
double weight = instance.getWeight();
return new InstanceWithWeight(
server,
Double.valueOf(weight).intValue()
);
})
.collect(Collectors.toList());
Server server = this.weightRandom(instanceWithWeights);
log.info("选中的server = {}", server);
return server;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
private class InstanceWithWeight {
private Server server;
private Integer weight;
}
/**
* 根据权重随机
* 算法参考 https://blog.csdn.net/u011627980/article/details/79401026
*
* @param list 实例列表
* @return 随机出来的结果
*/
private Server weightRandom(List<InstanceWithWeight> list) {
List<Server> instances = Lists.newArrayList();
for (InstanceWithWeight instanceWithWeight : list) {
int weight = instanceWithWeight.getWeight();
for (int i = 0; i <= weight; i++) {
instances.add(instanceWithWeight.getServer());
}
}
int i = new Random().nextInt(instances.size());
return instances.get(i);
}
}
WARNING
本段代码存在优化空间,只是用来演示思考的过程,不建议用于生产,如打算使用本方案实现,请参考以下两点优化:
- 简单起见,我直接把double型的权重(weight),转成了integer计算了,存在精度丢失。
- InstanceWithWeight太重了,在
weightRandom还得再两层for循环,还挺吃内存的,建议百度其他权重随机算法优化。不过实际项目一个微服务一般也就三五个实例,所以其实内存消耗也能忍受。不优化问题也不大。
方案2:利用Nacos Client的能力[推荐]
思路:
在阅读代码Nacos源码的过程中,发现Nacos Client本身就提供了负载均衡的能力,并且负载均衡算法正是我们想要的根据权重选择实例!
代码在 com.alibaba.nacos.api.naming.NamingService#selectOneHealthyInstance ,只要想办法调用到这行代码,就可以实现我们想要的功能啦!
代码:
@Slf4j
public class NacosWeightRandomV2Rule extends AbstractLoadBalancerRule {
@Autowired
private NacosDiscoveryProperties discoveryProperties;
@Override
public Server choose(Object key) {
DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
String name = loadBalancer.getName();
try {
Instance instance = discoveryProperties.namingServiceInstance()
.selectOneHealthyInstance(name);
log.info("选中的instance = {}", instance);
/*
* instance转server的逻辑参考自:
* org.springframework.cloud.alibaba.nacos.ribbon.NacosServerList.instancesToServerList
*/
return new NacosServer(instance);
} catch (NacosException e) {
log.error("发生异常", e);
return null;
}
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
}
方案3:最暴力的玩法
思路:
在阅读源码的过程中,发现如下代码:
// 来自:org.springframework.cloud.alibaba.nacos.ribbon.NacosServerList#getServers
private List<NacosServer> getServers() {
try {
List<Instance> instances = discoveryProperties.namingServiceInstance()
.selectInstances(serviceId, true);
return instancesToServerList(instances);
}
catch (Exception e) {
throw new IllegalStateException(
"Can not get service instances from nacos, serviceId=" + serviceId,
e);
}
}
这个NacosServerList 就是给Ribbon去做负载均衡的”数据源”!如果把这里的代码改成 com.alibaba.nacos.api.naming.NamingService#selectOneHealthyInstance 不也可以实现我们想要的功能吗?
也就是说,交给Ribbon的List永远只有1个实例!这样不管Ribbon用什么负载均衡,都随他便了。
代码:
1 参考NacosServerList的代码,重写NacosRibbonServerList
/**
* 参考org.springframework.cloud.alibaba.nacos.ribbon.NacosServerList
*/
@Slf4j
public class NacosRibbonServerList extends AbstractServerList<NacosServer> {
private NacosDiscoveryProperties discoveryProperties;
private String serviceId;
public NacosRibbonServerList(NacosDiscoveryProperties discoveryProperties) {
this.discoveryProperties = discoveryProperties;
}
@Override
public List<NacosServer> getInitialListOfServers() {
return getServers();
}
@Override
public List<NacosServer> getUpdatedListOfServers() {
return getServers();
}
private List<NacosServer> getServers() {
try {
Instance instance = discoveryProperties.namingServiceInstance()
.selectOneHealthyInstance(serviceId, true);
log.debug("选择的instance = {}", instance);
return instancesToServerList(
Lists.newArrayList(instance)
);
} catch (Exception e) {
throw new IllegalStateException(
"Can not get service instances from nacos, serviceId=" + serviceId,
e);
}
}
private List<NacosServer> instancesToServerList(List<Instance> instances) {
List<NacosServer> result = new ArrayList<>();
if (null == instances) {
return result;
}
for (Instance instance : instances) {
result.add(new NacosServer(instance));
}
return result;
}
public String getServiceId() {
return serviceId;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.serviceId = iClientConfig.getClientName();
}
}
2 编写配置类
/**
* 参考:org.springframework.cloud.alibaba.nacos.ribbon.NacosRibbonClientConfiguration
*/
@Configuration
public class NacosRibbonClientExtendConfiguration {
@Bean
public ServerList<?> ribbonServerList(IClientConfig config, NacosDiscoveryProperties nacosDiscoveryProperties) {
NacosRibbonServerList serverList = new NacosRibbonServerList(nacosDiscoveryProperties);
serverList.initWithNiwsConfig(config);
return serverList;
}
}
3 添加注解,让上面的NacosRibbonClientExtendConfiguration成为Ribbon的默认配置。
// ...其他注解
@RibbonClients(defaultConfiguration = NacosRibbonClientExtendConfiguration.class)
public class ConsumerMovieApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerMovieApplication.class, args);
}
}
注意 :
务必注意,将 NacosRibbonClientExtendConfiguration 放在ComponentScan上下文(默认是启动类所在包及其子包)以外!!!
总结与对比
- 方案1:是最容易想到的玩法。
- 方案2:是个人目前最喜欢的方案。首先简单,并且都是复用Nacos/Ribbon现有的代码——而Ribbon/Nacos本身都是来自于大公司生产环境,经过严苛的生产考验。
- 方案3:太暴力了,把Ribbon架空了。此方案中,扔给Ribbon做负载均衡选择时,List只有1个元素,不管用什么算法去算,最后总是会返回这个元素!
思考
既然Nacos Client已经有负载均衡的能力,Spring Cloud Alibaba为什么还要去整合Ribbon呢?
个人认为,这主要是为了符合Spring Cloud标准。Spring Cloud Commons有个子项目
spring-cloud-loadbalancer,该项目制定了标准,用来适配各种客户端负载均衡器(虽然目前实现只有Ribbon,但Hoxton就会有替代的实现了)。Spring Cloud Alibaba遵循了这一标准,所以整合了Ribbon,而没有去使用Nacos Client提供的负载均衡能力。
边栏推荐
- Scheduling with Testing
- 70-根因分析-oracle数据库突发性能问题,谁来背这个锅
- 密码学系列之:PKI的证书格式表示X.509
- [proteus simulation] H-bridge drive DC motor composed of triode + key forward and reverse control
- 他98年的,我玩不过他...
- [graduation season] step by step? Thinking about four years of University by an automation er
- CVPR 2022 oral | video text pre training new SOTA, HKU and Tencent arc lab launched excuse task based on multiple-choice questions
- 【深入理解TcaplusDB技术】单据受理之建表审批
- Dynamicdatabasesource, which supports the master-slave database on the application side
- 92-几个用match_recognize SQL写法示例
猜你喜欢

6月第3周B站榜单丨飞瓜数据UP主成长排行榜(哔哩哔哩平台)发布!

科技云报道:东数西算不止于“算”,更需“新存储”
mysql8.0忘记密码的详细解决方法

Easydss problem and solution summary
![[graduation season] step by step? Thinking about four years of University by an automation er](/img/56/86b5dbb7ce7cf924c85ed1071b1e6c.jpg)
[graduation season] step by step? Thinking about four years of University by an automation er

【毕业季】走一步看一步?一个自动化er对大学四年的思考

采用QTest进行数据集测试-性能测试-GUI测试

NFT 中可能存在的安全漏洞

From perceptron to transformer, a brief history of deep learning

阿里云视频点播播放出错,控制台访问出现code:4400
随机推荐
AAAI 2022 | 传统GAN修改后可解释,并保证卷积核可解释性和生成图像真实性
深度学习常用损失函数总览:基本形式、原理、特点
Using span method to realize row merging of multi-layer table data
Stochastic Adaptive Dynamics of a Simple Market as a Non-Stationary Multi-Armed Bandit Problem
Containerd容器运行时(2):yum安装与二进制安装,哪个更适合你?
Introduction of neural network (BP) in Intelligent Computing
什么?你居然不会微信分身
【已解决】--go_out: protoc-gen-go: Plugin failed with status code 1.
Lora technology -- Lora signal changes from data to Lora spread spectrum signal, and then from RF signal to data through demodulation
软件测试——测试用例设计&测试分类详解
CVPR 2022 Oral | 视频文本预训练新SOTA,港大、腾讯ARC Lab推出基于多项选择题的借口任务
Code to Image Converter | 代码生成漂亮图片工具
Oh, my God, it's a counter attack by eight part essay
播放增长900w,B站用户叫好叫座的恰饭总结
Which securities firm is better to choose for opening an account in flush? Is it safe to open a mobile account?
Introduction to JWT
底部菜单添加的链接无法跳转到二级页面的问题
Introduction of neural networks for Intelligent Computing (Hopfield network DHNN, CHNN)
【513. 找树左下角的值】
[proteus simulation] H-bridge drive DC motor composed of triode + key forward and reverse control