ribbon设置权重_扩展Ribbon支持Nacos权重的三种方式

本节来探讨如何扩展Ribbon,让其支持Nacos的权重配置,笔者总结了三种方案。

方案1:自己实现负载均衡规则

思路:

自己首先一个Ribbon负载均衡规则就可以了。

权重配置啥的,都可以在实例信息中获取到。

自己基于权重配置,计算出一个实例即可。

代码:

@Slf4j

public class NacosWeightRandomV1Rule extends AbstractLoadBalancerRule {

@Override

public void initWithNiwsConfig(IClientConfig iClientConfig) {

}

@Override

public Server choose(Object key) {

Listservers = this.getLoadBalancer().getReachableServers();

ListinstanceWithWeights = 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(Listlist) {

Listinstances = 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 ListgetServers() {

try {

Listinstances = 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{

private NacosDiscoveryProperties discoveryProperties;

private String serviceId;

public NacosRibbonServerList(NacosDiscoveryProperties discoveryProperties) {

this.discoveryProperties = discoveryProperties;

}

@Override

public ListgetInitialListOfServers() {

return getServers();

}

@Override

public ListgetUpdatedListOfServers() {

return getServers();

}

private ListgetServers() {

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 ListinstancesToServerList(Listinstances) {

Listresult = 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提供的负载均衡能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值