历下区网站建设公司/一台电脑赚钱的门路
一、前言
本文将自定义负载均衡策略来实现权限策略
和同一集群优先使用带版本策略
,主要解决在本地开发环境启动相同服务时,调用服务会跑到其他人那里。
简要逻辑:在通过nacos注册服务时,添加version
参数绑定本地服务ip信息,在服务调用时,去获取nacos上注册服务信息,通过version
参数条件去指定调用具体服务。
ex: 服务A调用服务B
如果服务B的version参数值和服务A的version参数值一致,即会优先调用与服务A相同version值的服务B
如果没有与服务A相同version值的服务B,再去随机按权重调用服务B
环境:
- spring-boot-dependencies 2.3.2.RELEASE
- spring-cloud-dependencies Hoxton.SR8
- spring-cloud-alibaba-dependencies 2.2.3.RELEASE
二、自定义负载均衡策略
1、自定义负载均衡策略-权重
@Slf4j
public class BalancerWeightRule extends AbstractLoadBalancerRule {@Autowiredprivate NacosServiceManager nacosServiceManager;@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties;@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig) {// 读取配置文件, 并且初始化, ribbon内部基本上用不上}/*** 这个方法是实现负载均衡策略的方法*/@Overridepublic Server choose(Object key) {try {// 1、获取当前服务的分组名称String groupName = this.nacosDiscoveryProperties.getGroup();// 2、获取当前服务的负载均衡器BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer();// 3、获取目标服务的服务名String serviceName = baseLoadBalancer.getName();// 4、获取nacos提供的服务注册apiNamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());// 5、根据目标服务名称和分组名称去获取服务实例,nacos实现了权重的负载均衡算法 false: 及时获取nacos注册服务信息Instance toBeChooseInstance = namingService.selectOneHealthyInstance(serviceName, groupName, false);BalancerInstanceUtil.printInstance(BalancerRuleTypeEnum.WEIGHT, toBeChooseInstance);return new NacosServer(toBeChooseInstance);} catch (NacosException e) {log.error("自定义负载均衡策略-权重 调用异常: ", e);return null;}}}
2、自定义负载均衡策略-同一集群优先使用带版本实例
@Slf4j
public class BalancerVersionRule extends AbstractLoadBalancerRule {@Autowiredprivate NacosServiceManager nacosServiceManager;@Autowiredprivate NacosDiscoveryProperties nacosDiscoveryProperties;@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig) {}@Overridepublic Server choose(Object o) {try {// 1、获取当前服务的分组名称、集群名称、版本号String groupName = this.nacosDiscoveryProperties.getGroup();String clusterName = this.nacosDiscoveryProperties.getClusterName();String version = this.nacosDiscoveryProperties.getMetadata().get("version");// 2、获取当前服务的负载均衡器BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer();// 3、获取目标服务的服务名String serviceName = baseLoadBalancer.getName();// 4、获取nacos提供的服务注册apiNamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());// 5、获取所有服务名为serviceName的服务实例 false: 及时获取nacos注册服务信息List<Instance> allInstanceList = namingService.getAllInstances(serviceName, groupName, false);// 6、过滤有相同集群的服务实例List<Instance> sameClusterInstanceList = Lists.newLinkedList();for (Instance instance : allInstanceList) {if (instance.getClusterName().equals(clusterName)) {sameClusterInstanceList.add(instance);}}// 7、过滤相同版本的服务实例List<Instance> sameVersionInstanceList = Lists.newLinkedList();for (Instance instance : sameClusterInstanceList) {if (version.equals(instance.getMetadata().get("version"))) {sameVersionInstanceList.add(instance);}}// 8、选择合适的服务实例Instance toBeChooseInstance;if (CollectionUtils.isEmpty(sameVersionInstanceList)) {toBeChooseInstance = WeightedBalancer.chooseInstanceByRandomWeight(sameClusterInstanceList);BalancerInstanceUtil.printInstance(BalancerRuleTypeEnum.VERSION_WEIGHT, toBeChooseInstance);} else {toBeChooseInstance = WeightedBalancer.chooseInstanceByRandomWeight(sameVersionInstanceList);BalancerInstanceUtil.printInstance(BalancerRuleTypeEnum.VERSION, toBeChooseInstance);}return new NacosServer(toBeChooseInstance);} catch (NacosException e) {log.error("Nacos同一集群带版本优先调用异常: ", e);return null;}}}
版本策略所需随机权重类
public class WeightedBalancer extends Balancer {public static Instance chooseInstanceByRandomWeight(List<Instance> instanceList) {// 这是父类Balancer自带的根据随机权重获取服务的方法.return getHostByRandomWeight(instanceList);}}
3、启用自定义负载均衡策略
可参考 https://cloud.spring.io/spring-cloud-static/Dalston.SR5/multi/multi_spring-cloud-ribbon.html#_customizing_the_ribbon_client
@Configuration
@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)
public class CustomRibbonConfig {}
@Slf4j
@Data
@Configuration
public class GlobalRibbonConfig {@Value("${ribbon.rule-type:}")private String ruleType;@Beanpublic IRule getRule() {// 自定义负载均衡策略BalancerRuleTypeEnum balancerRuleTypeEnum = BalancerRuleTypeEnum.getEnum(this.ruleType);log.info("使用自定义负载均衡策略:[{}]", balancerRuleTypeEnum.getDesc());switch (balancerRuleTypeEnum) {case WEIGHT:// 权重return new BalancerWeightRule();case VERSION:// 同一集群优先带版本实例return new BalancerVersionRule();default:// 默认权重return new BalancerWeightRule();}}}
通过配置ribbon.rule-type
参数值来选择使用哪一种负载均衡策略
ribbon:rule-type: version
4、负载均衡策略枚举类和工具类
@Slf4j
@Getter
@AllArgsConstructor
public enum BalancerRuleTypeEnum {/*** 权重*/WEIGHT("weight", "权重"),/*** 同一集群使用相同版本*/VERSION("version", "同一集群使用相同版本"),/*** 同一集群无相同版本,使用权重*/VERSION_WEIGHT("version_weight", "同一集群无相同版本,使用权重");/*** 规则类型*/private final String type;/*** 规则描述*/private final String desc;private static final List<BalancerRuleTypeEnum> LIST = Lists.newArrayList();static {LIST.addAll(Arrays.asList(BalancerRuleTypeEnum.values()));}/*** 根据指定的规则类型查找相应枚举类** @param type 规则类型* @return 规则类型枚举信息* @author zhengqingya* @date 2020/9/13 18:46*/public static BalancerRuleTypeEnum getEnum(String type) {for (BalancerRuleTypeEnum itemEnum : LIST) {if (itemEnum.getType().equals(type)) {return itemEnum;}}log.warn("未找到指定的负载均衡策略,默认权重策略!");return WEIGHT;}}
@Slf4j
public class BalancerInstanceUtil {public static void printInstance(BalancerRuleTypeEnum ruleTypeEnum, Instance instance) {if (instance == null) {return;}log.info("自定义负载均衡策略-[{}] serviceName: [{}], clusterName: [{}], ip: [{}] port: [{}]",ruleTypeEnum.getDesc(),instance.getServiceName(),instance.getClusterName(),instance.getIp(),instance.getPort());}}
三、配置ribbon饥饿加载模式
主要解决:在服务启动后,第1次访问可能会报错
产生原因:ribbon服务调用默认使用懒加载模式,即在调用的时候才会去创建相应的client
ribbon:# 配置饥饿加载模式eager-load:# 开启饥饿加载模式enabled: true# 指定需要饥饿加载的服务名clients:- "demo"- "system"- "tool"
四、本文案例demo源码
https://gitee.com/zhengqingya/small-tools
今日分享语句:
我不敢休息,因为我没有存款。我不敢说累,因为我没有成就。我不敢偷懒,因为我还要生活。我能放弃选择,但是我不能选择放弃。坚强拼搏是我唯一的选择。