一、前言
专注app软件定制开发本文将自定义策略来实现权限策略
和专注app软件定制开发同一集群优先使用带版本策略
,专注app软件定制开发主要解决在本地开发环专注app软件定制开发境启动相同服务时,调用服务会跑到其他人那里。
简要逻辑:在通过注册服务时,添加version
参数绑定本地服务ip信息,在服务调用时,去获取nacos上注册服务信息,通过version
参数条件去指定调用具体服务。
ex: 服务A调用服务B
如果服务B的参数值和服务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、自定义负载均衡策略-权重
@Slf4jpublic class BalancerWeightRule extends AbstractLoadBalancerRule { @Autowired private NacosServiceManager nacosServiceManager; @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { // 读取配置文件, 并且初始化, ribbon内部基本上用不上 } /** * 这个方法是实现负载均衡策略的方法 */ @Override public Server choose(Object key) { try { // 1、获取当前服务的分组名称 String groupName = this.nacosDiscoveryProperties.getGroup(); // 2、获取当前服务的负载均衡器 BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) this.getLoadBalancer(); // 3、获取目标服务的服务名 String serviceName = baseLoadBalancer.getName(); // 4、获取nacos提供的服务注册api NamingService 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; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
2、自定义负载均衡策略-同一集群优先使用带版本实例
@Slf4jpublic class BalancerVersionRule extends AbstractLoadBalancerRule { @Autowired private NacosServiceManager nacosServiceManager; @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { } @Override public 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提供的服务注册api NamingService 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; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
版本策略所需随机权重类
public class WeightedBalancer extends Balancer { public static Instance chooseInstanceByRandomWeight(List<Instance> instanceList) { // 这是父类Balancer自带的根据随机权重获取服务的方法. return getHostByRandomWeight(instanceList); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
3、启用自定义负载均衡策略
可参考
@Configuration@RibbonClients(defaultConfiguration = GlobalRibbonConfig.class)public class CustomRibbonConfig {}
- 1
- 2
- 3
- 4
- 5
@Slf4j@Data@Configurationpublic class GlobalRibbonConfig { @Value("${ribbon.rule-type:}") private String ruleType; @Bean public 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(); } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
通过配置ribbon.rule-type
参数值来选择使用哪一种负载均衡策略
ribbon: rule-type: version
- 1
- 2
4、负载均衡策略枚举类和工具类
@Slf4j@Getter@AllArgsConstructorpublic 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; }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
@Slf4jpublic 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() ); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
三、配置ribbon饥饿加载模式
主要解决:在服务启动后,第1次访问可能会报错
产生原因:ribbon服务调用默认使用懒加载模式,即在调用的时候才会去创建相应的client
ribbon: # 配置饥饿加载模式 eager-load: # 开启饥饿加载模式 enabled: true # 指定需要饥饿加载的服务名 clients: - "demo" - "system" - "tool"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
四、本文案例demo源码
今日分享语句:
我不敢休息,因为我没有存款。我不敢说累,因为我没有成就。我不敢偷懒,因为我还要生活。我能放弃选择,但是我不能选择放弃。坚强拼搏是我唯一的选择。