• 基于nacos netflix loadbalancer灰度发布策略


    一,实现原理

    利用nacos元数据,给服务发起方和被调用方定义标签。相同标签的优先调用。

    二,实现场景

    假设 A,B两个服务,各存在4个节点,且版本都是V1

    A1(V1)  B1(V1)

    A2(V1)  B2(V1)

    A3(V1)  B3(V1)

    A4(V1)  B4(V1)

    更新版本后

    A1(V2)  B1(V2)

    A2(V1)  B2(V1)

    A3(V1)  B3(V1)

    A4(V1)  B4(V1)

    更新后V2的相互调用,V1的相互调用。

    三,关键代码

    参考NacosRule类 ,更复杂的情况可以依例扩展

    pom.xml

    1. <dependencies>
    2. <dependency>
    3. <groupId>com.alibaba.cloudgroupId>
    4. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframework.bootgroupId>
    8. <artifactId>spring-boot-configuration-processorartifactId>
    9. <optional>trueoptional>
    10. dependency>
    11. <dependency>
    12. <groupId>org.projectlombokgroupId>
    13. <artifactId>lombokartifactId>
    14. dependency>
    15. dependencies>
    GrayConstant.java
    1. package com.rutron.canary;
    2. /**
    3. * @author liwenchao
    4. */
    5. public class GrayConstant {
    6. public static final String GRAY_TAG = "version";
    7. }
    CanaryBalancerRule.java
    1. package com.rutron.canary;
    2. import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
    3. import com.alibaba.cloud.nacos.NacosServiceManager;
    4. import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
    5. import com.alibaba.cloud.nacos.ribbon.NacosServer;
    6. import com.alibaba.nacos.api.naming.NamingService;
    7. import com.alibaba.nacos.api.naming.pojo.Instance;
    8. import com.netflix.client.config.IClientConfig;
    9. import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    10. import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
    11. import com.netflix.loadbalancer.Server;
    12. import lombok.extern.slf4j.Slf4j;
    13. import org.apache.commons.lang3.StringUtils;
    14. import org.springframework.beans.factory.annotation.Autowired;
    15. import org.springframework.util.CollectionUtils;
    16. import java.util.ArrayList;
    17. import java.util.List;
    18. import java.util.Map;
    19. /**
    20. * @author liwenchao
    21. */
    22. @Slf4j
    23. public class CanaryBalancerRule extends AbstractLoadBalancerRule {
    24. @Autowired
    25. private NacosDiscoveryProperties nacosDiscoveryProperties;
    26. @Autowired
    27. private NacosServiceManager nacosServiceManager;
    28. public CanaryBalancerRule() {
    29. }
    30. @Override
    31. public void initWithNiwsConfig(IClientConfig iClientConfig) {
    32. }
    33. @Override
    34. public Server choose(Object key) {
    35. try {
    36. String clusterName = this.nacosDiscoveryProperties.getClusterName();
    37. String group = this.nacosDiscoveryProperties.getGroup();
    38. Map ribbonAttributes = this.nacosDiscoveryProperties.getMetadata();
    39. DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
    40. String serviceName = loadBalancer.getName();
    41. NamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());
    42. List allInstances = namingService.selectInstances(serviceName, group, true);
    43. List grayInstances = new ArrayList<>();
    44. List noneGrayInstances = new ArrayList<>();
    45. Instance toBeChooseInstance;
    46. if (CollectionUtils.isEmpty(allInstances)) {
    47. log.warn("no instance in service {}", serviceName);
    48. return null;
    49. } else {
    50. if (StringUtils.isNotBlank(clusterName)) {
    51. for (Instance instance : allInstances) {
    52. Map metadata = instance.getMetadata();
    53. //当前服务的灰度标签和被调用的服务的灰度标签比,相同则灰色
    54. if (!ribbonAttributes.containsKey(GrayConstant.GRAY_TAG) || !metadata.containsKey(GrayConstant.GRAY_TAG)) {
    55. noneGrayInstances.add(instance);
    56. } else if (ribbonAttributes.get(GrayConstant.GRAY_TAG).trim().equalsIgnoreCase(metadata.get(GrayConstant.GRAY_TAG).trim())) {
    57. grayInstances.add(instance);
    58. } else if (!StringUtils.isBlank(metadata.get(GrayConstant.GRAY_TAG))) {
    59. noneGrayInstances.add(instance);
    60. }
    61. }
    62. }
    63. if (grayInstances.size() > 0) {
    64. toBeChooseInstance = ExtendBalancer.getHostByRandomWeight2(grayInstances);
    65. return new NacosServer(toBeChooseInstance);
    66. }
    67. if (noneGrayInstances.size() > 0) {
    68. toBeChooseInstance = ExtendBalancer.getHostByRandomWeight2(noneGrayInstances);
    69. } else {
    70. toBeChooseInstance = ExtendBalancer.getHostByRandomWeight2(allInstances);
    71. }
    72. return new NacosServer(toBeChooseInstance);
    73. }
    74. } catch (Exception e) {
    75. log.warn("NacosRule error", e);
    76. return null;
    77. }
    78. }
    79. }
    RibbonAutoConfiguration.java
    1. package com.rutron.canary;
    2. import com.netflix.loadbalancer.IRule;
    3. import org.springframework.context.annotation.Bean;
    4. /**
    5. * @author liwenchao
    6. */
    7. public class RibbonAutoConfiguration {
    8. /**
    9. * 全局配置指定负载均衡策略
    10. */
    11. @Bean
    12. public IRule canaryBalancerRule() {
    13. return new CanaryBalancerRule();
    14. }
    15. }

    spring.factories

    1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    2. com.rutron.canary.RibbonAutoConfiguration

     调用者和被调用者添加元数据

    {

        "preserved.register.source": "SPRING_CLOUD",

        "version":"v2"

    }

  • 相关阅读:
    TS 变量类型
    spring boot整合常用redis客户端(Jedis、Lettuce、RedisTemplate、Redisson)常见场景解决方案
    如何建立编程思想和提高编程思想
    学习java的第二十天。。。(多态)
    二分查找算法
    jQuery【jQuery树遍历、jQuery动画(一)、jQuery动画(二)】(四)-全面详解(学习总结---从入门到深化)
    中科磐云—2022广东木马信息获取解析
    游戏初步——发牌程序(控制台版)以及一些扩展(python)
    从全局视角看数据结构
    西宾得到语音下载工具(dedaodown
  • 原文地址:https://blog.csdn.net/echizao1839/article/details/127409664