Spring Cloud初探之自定义负载均衡策略(五)
背景
这是Spring Cloud Alibaba组件初探的第五篇文章,前面四篇描述了Nacos如何适配Postgresql数据库,微服务注册,客户端负载均衡的使用,通过定时器更新服务实例的元数据和权重值。这篇描述如何自定义服务均衡策略。
Spring Cloud的load balance支持轮询、随机负载策略,阿里也提供了NacosLoadBalancer均衡器(支持集群+权重)。框架默认采用的是轮询的方式。
有时候,项目可能有一些订制化的需求,需要根据采集的其它指标做负载均衡。例如:通过服务的CPU利用率,内存占用率,磁盘空间等指标做个性化的负载均衡调度。当然,这些指标可以折算成权重,再根据权重调度。但将指标折算成权重后,就丢失了原始信息了,特别是多个指标加权,折算结果也不一定合理,反而可能增加调度算法的实现难度。
在指标加权折成算权重比较困难的情况下,可以考虑将指标的原始信息存储在服务实例的元数据里面,让负载均衡器从元数据中拿到原始数据做处理。
定义自己的负载均衡器
定义MyLoadBalancer类,实现ReactorServiceInstanceLoadBalancer提供的接口。可以参考RoundRobinLoadBalancer和RandomLoadBalancer的实现。choose()和processInstanceResponse()这两个方法代码可以直接拿过来用,真正需要调整的是getInstanceResponse()中的服务实例选择逻辑。
下面是RandomLoadBalancer中的getInstanceResponse()实现:
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {if (instances.isEmpty()) {if (log.isWarnEnabled()) {log.warn("No servers available for service: " + this.serviceId);}return new EmptyResponse();} else {int index = ThreadLocalRandom.current().nextInt(instances.size());ServiceInstance instance = (ServiceInstance)instances.get(index);return new DefaultResponse(instance);}}
可以看到,样例代码通过一个随机函数生成下标索引,再根据索引从实例列表中取服务实例。
如果想要基于CPU利用率来做负载均衡:每次选择CPU利用率最低的服务来使用。参考RandomLoadBalancer的实现,在MyLoadBalancer类中实现如下getInstanceResponse()方法:
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {if (instances.isEmpty()) {LOGGER.error("No servers available for service:{} ", serviceId);return new EmptyResponse();}/*** 选择一个CPU利用率最低的服务实例返回.*/List<CPUUsageCompare> compareModelList = CPUUsageCompare.valueOf(instances);Optional<CPUUsageCompare> minUsageInstance = compareModelList.stream().min((o1, o2) -> {if (o1.getCpuUsage() > o2.getCpuUsage()) {return 1;} else if (o1.getCpuUsage() < o2.getCpuUsage()) {return -1;} else {return 0;}});if (minUsageInstance.isPresent()) {return new DefaultResponse(minUsageInstance.get().getServiceInstance());} else {return new EmptyResponse();}}
CPUUsageCompare是把服务实例和从元数据中提取出的CPU利用率数据做了一下封装,方便做大小比较。完整代码参看文末的github仓库地址。
注入自定义的负载均衡器
/*** 加载自定义的均衡算法配置** @author neo* @since 2025/4/24* @version 1.0*/
@LoadBalancerClient(name = "cloud-server-one", configuration = MyLoadBalanceConfig.class)
public class MyLoadBalanceConfig {@Beanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new MyLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}
}
配置调用cloud-server-one服务的接口时使用自定义的负载均衡器。
github仓库地址:https://github.com/ylforever/neo-spring-cloud-server