MSE Nacos自定义标签灰度

为了解决基于IP灰度的局限性,MSE Nacos对灰度发布进行了功能升级,支持自定义标签灰度的能力,结合原先的IP灰度,可以给业务提供更加灵活更加易用的灰度发布能力,为业务稳定性保驾护航。

背景介绍

配置中心被广泛使用

配置中心是Nacos的核心功能之一,允许在线修改应用配置而无需重启,降低了软件构建及部署的成本,提升了效率,为业务发展提速。

image

上图展示了Nacos在微服务、高可用、前端、数据库等多个领域的广泛应用,配置中心在这些场景中扮演关键角色,如流量管理、路由设定、应急响应、业务开关与数据库配置等,确保这些配置的准确性对于线上业务的稳定运行至关重要。

配置变更的风险

动态配置变更能显著提升软件迭代效率,但也引入了稳定性风险,对线上配置的误操作,可能导致线上程序执行出错,进而对业务产生影响。若变更流程不完善,动态配置变更从某种角度上来说会扩大线上稳定性问题的敞口,业界由于配置变更导致的故障时有发生,因此对于配置的变更管控是非常必要的。

出于稳定性考虑,变更需具有可灰度,可监控,可回滚三个基本要求:

  • 可灰度:要求任何变更都可以控制其生效范围,在变更过程中可逐步扩大生效范围。

  • 可监控:要求对业务的各项指标都有可视化展示,可正确清晰地反应业务的运行状态。

  • 可回滚:在变更期间,如观测到业务异常,可以快速使业务回退至变更前的状态。

灰度发布是配置中心用于控制配置变更风险的一个非常重要且基础的功能。

一个规范的配置变更流程如下图所示:

image

先选取一部分低风险应用服务器作为第一个版本的灰度,下发新配置,观察服务器的系统及业务指标,确认业务正常后,逐步扩大灰度范围,直至发布正式版本完成整体的配置变更流程,如果期间业务出现异常,选择终止灰度,先前已灰度的服务器也同时回滚至变更前的配置,以快速恢复业务。

基于IP灰度的局限

在之前的版本中,Nacos 提供了基于 IP 地址的灰度发布方式,用户在发布正式版本配置前,可以选择一些 IP 地址下发新配置进行验证,确认业务正常,观察期过后,选择全量发布。

image

对于小型应用,基于IP的灰度发布已足够。但对中大型应用而言,一个配置可能被大量应用节点订阅,这些节点可能来自不同业务,对线上业务的影响范围也不同。当节点IP数量较大时,易用性大大降低。IP地址由底层基础网络设施决定,难以直接关联具体业务。扩大灰度范围时,需手动筛选符合特定业务需求的IP列表。此外,在K8s容器化环境中,节点重启后IP变化可能导致灰度策略失效。

自定义标签灰度

自定义标签灰度允许应用根据实际场景给不同的节点设置不同的标签,如应用,机房,环境等标签,例如在阿里集团内部,同一个应用在不同开发分支下,可以给各开发分支部署的节点打上相应的标签,借助标签灰度的能力实现不同的项目环境下发不同的配置内容。以下我们将介绍应用如何接入自定义标签灰度的能力。

image.png

版本要求

  • 为了实现自定义应用标签灰度功能,您需要确保开源Nacos-Client的版本更新至2.3.2或更高版本。

  • 使用通过环境变量注入标签的能力,需升级Nacos-Client至2.4.2及以上。

  • 对于MSE Nacos,其版本应升级至2.2.3.3或以上,以支持应用标签灰度特性。

单标签灰度

对于一些中小型应用来说,使用单标签灰度就可以满足自定义灰度的需求。

客户端设置应用标签

在您完成客户端和服务端版本升级至所需版本后,接下来可以为您的应用添加自定义标签以实现灰度发布。

如何设置应用标签

应用标签采用键值对(key-value)形式,以下是设置应用标签的三种常见方式:

  1. 使用Properties属性设置标签:nacos.config.gray.label是Nacos内置的默认配置灰度标签,您可以通过设置nacos.config.gray.label={value}来给应用打标。

    Properties properties = new Properties();
    properties.put(PropertyKeyConst.SERVER_ADDR, "{server addr}");
    // 添加其他配置项...
    properties.put("nacos.config.gray.label", "yourgrayname");
    ConfigFactory.createConfigService(properties);
  2. 通过JVM参数设置标签:在启动应用的命令行中,添加-Dnacos.config.gray.label={value}参数。

    java -Dnacos.config.gray.label=yourgrayname -jar your-app.jar
  3. 通过环境变量设置标签:在环境变量中设置nacos_config_gray_label为{value}

    export nacos_config_gray_label=yourgrayname
设置方式的作用范围与优先级
  • Properties属性:只对当前ConfigService对象生效,作用范围最小。

  • JVM参数:对当前进程内的所有ConfigService生效。

  • 环境变量:对当前节点上的所有ConfigService生效。

  • 优先级:当三种方式设置的标签key存在重复时,读取的优先级从高到低依次为:properties > JVM参数 > 环境变量。

服务端发布标签灰度

查看监听者标签

在客户端设置完应用标签,并重启应用后,可以通过MSE Nacos控制台查看配置的监听查询列表,查看每个监听者携带的标签。

image

发布灰度标签配置

在 MSE Nacos控制台配置列表页面,单击编辑配置,选择基于标签灰度发布,设置灰度版本名称,选择应用节点的标签键值对,可以看到预期匹配到的应用节点数量以及节点列表,在界面右侧配置内容框中编辑配置内容,单击发布灰度完成配置发布。

image

发布灰度标签版本后,打开配置详情页,单击配置内容页签,可以看到正式Beta两个版本。

image

切换至监听查询页签,可以看到对应的业务节点当前的匹配的版本, 展示的版本为Beta({灰度版本名称}), Md5为对应版本的Md5,推送状态为推送成功。

image

此外,在推送轨迹页签也可以看到标签发布以及客户端查询灰度版本的轨迹,在节点的配置推送轨迹详情中可以看到具体推送的配置版本。

image

在进行第一批灰度观察后,可以通过扩大编辑标签的值范围来逐步扩大灰度,直到进行全量发布,单击全量发布后,将停止对应的灰度版本。如果在灰度过程中发现业务异常,可以单击停止灰度进行一键自动回滚。

以下我们简单介绍几种常见的逐步扩大灰度的用法:

方法一:基于应用标签的灰度发布

  1. 为不同应用设置各自的标签:给应用A的所有服务器分配nacos.config.gray.label=A的标签;给应用B的所有服务器分配nacos.config.gray.label=B

  2. 初步灰度部署:首先,仅针对带有nacos.config.gray.label=A标签的应用A进行新版本的灰度测试。

  3. 扩展灰度范围:当确认新版本在应用A上运行良好后,可以通过修改灰度规则(如改为nacos.config.gray.label=A,B),将应用B也纳入到灰度测试中。

方法二:基于环境分组的灰度发布

  1. 将生产环境中的机器划分为多个小组,并分别为这些小组指定不同的标签值,例如nacos.config.gray.label=gray1,nacos.config.gray.label=gray2,nacos.config.gray.label=gray3等。同时,保持未参与灰度测试的正式环境使用nacos.config.gray.label=online作为其标签。

  2. 通过调整配置文件中的标签值来控制哪些特定环境或分组能够接收到最新的灰度版本更新。

  3. 在每个阶段结束后,根据实际表现逐渐增加更多具有相同标签属性的服务器进入灰度测试流程,直到最终覆盖整个目标群体。

灰度发布的后续步骤

  • 完成每次小规模灰度上线之后,请密切监控相关业务指标。

  • 如果一切正常,在经过一段观察期后,您可以进一步扩大灰度测试的影响范围,直至包含所有预期的目标节点。

  • 当所有的灰度测试均表明新版软件稳定可靠时,则可执行全量发布操作,使当前的灰度版本成为正式版本。成功发布正式版本后,当前的灰度版本将会终止。

这种方法允许开发者以一种更加谨慎且可控的方式推出新的功能或改进,从而减少潜在风险并提高用户体验。

多标签灰度

在处理较为复杂的中大型应用时,单一标签可能难以满足业务需求的多样性。MSE提供了灵活的标签管理机制,不对标签键(key)做严格限制,允许用户根据自身业务特性自定义标签键,并支持为同一应用配置多个标签,以实现更精细化的服务管理和灰度发布策略。接下来,我们将详细介绍如何为您的业务节点添加和管理多个标签键值对,帮助您更好地利用这一功能来应对复杂的应用场景。

客户端设置应用标签

和设置单个标签类似,客户端可以在properties及JVM参数,环境变量中设置多个标签。

  1. 使用Properties属性设置标签:nacos.app.conn.labels=k1=v1,k2=v2,k3=v3

    //1.properties形式传入
    Properties properties = new Properties();
    properties.put(PropertyKeyConst.SERVER_ADDR, "your endpoint");
    properties.put("project.name", "your app name");
    properties.put("nacos.app.conn.labels","app=demo,site=hangzhou-c,otherkey=othervaue");
  2. 通过JVM参数设置标签:nacos.app.conn.labels=k1=v1,k2=v2,k3=v3

    //2.JVM参数设置
    设置启动参数-Dnacos.app.conn.labels=app=demo,site=hangzhou-c,otherkey=othervaue
  3. 通过环境变量设置标签:nacos_app_conn_labels=k1=v1,k2=v2,k3=v3

    //3.env环境变量指定
    设置环境变量 nacos_app_conn_labels=app=demo,site=hangzhou-c,otherkey=othervaue
    
    NacosConfigService configService = new NacosConfigService(properties);
    
    String dataId = "gray_test_dataid";
    String group = "test-group";
            
    configService.addListener(dataId, group, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }
                
            @Override
            public void receiveConfigInfo(String configInfo) {
                System.out.println("receiveConfig:" + configInfo);
            }
    });
  4. 除了通过上述三种参数设置之外,对于较为复杂的标签读取逻辑,还可以选择实现SPI接口来配置标签。Nacos-Client 提供了一个定义自定义应用标签的 SPI 机制。您需要实现 com.alibaba.nacos.common.labels.LabelsCollector 接口,并将其实现类通过在 META-INF/services/ 目录下发布为服务提供者(Service Provider Interface, SPI)。这样做的好处是能够更加灵活地控制和扩展标签的收集与处理逻辑,以适应不同应用场景下的需求。

    自定义配置标签代码示例

    package your.demo.test;
    
    import com.alibaba.nacos.common.labels.LabelsCollector;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    /**
     * TestLabelsCollector.
     *
     * @author yourname
     */
    public class TestLabelsCollector implements LabelsCollector {
        
        @Override
        public String getName() {
            return "testlables";
        }
        
        @Override
        public Map<String, String> collectLabels(Properties properties) {
            Map<String, String> labels = new HashMap<>();
            labels.put("test", "implements your lables logic");
            return labels;
        }
    
      
        @Override
        public int getOrder() {
            return 1;
        }
    }

注意事项:

为了确保应用程序在使用标签进行灰度发布时能够平稳运行,Nacos对标签的键值做了一些约束:

  • 允许字符:标签的键(key)与值(value)部分仅支持使用英文大小写字母、数字、下划线_、短横线-以及点.。任何包含非上述字符的标签将被系统忽略。

  • 格式要求:当通过nacos.app.conn.labels参数指定多个键值对时,请确保它们按照k1=v1,k2=v2,k3=v3的格式排列。例如,若输入为k1=v1,k2,则只有k1=v1会被识别,而k2因缺少对应的值而被忽略。

  • 数量限制:对于每个应用节点而言,最多可以配置10个标签键值对。一旦超出此数目,系统将随机移除多余的标签。因此,在规划应用所需标签时,请考虑这一上限因素。

此外,在设定灰度发布的匹配规则方面:

当前版本支持基于多个不同的标签值来筛选符合条件的节点列表,但为了降低功能的复杂度,暂不支持在同一灰度规则内同时指定多个标签键进行复合匹配。即,无法直接利用类似k1=v1&&k2=v2或者k1=v1||k2=v2这样的逻辑表达式来精确控制或扩展灰度测试范围。

多灰度版本并行

适用场景

MSE Nacos 支持在一个配置下发布多个灰度版本,支持根据不同条件灵活地为不同的服务节点提供定制化的配置信息。例如,您可以为满足 k1=v1 条件的节点下发 graycontent1 的配置内容,同时为满足 k1=v2 条件的节点分配 graycontent2 的配置内容。

操作步骤

编辑配置的面板中,单击“+”创建新的灰度版本。

重要

MSE对一个配置所发布的最大灰度版本数量有一定限制,默认最大支持5个标签灰度的版本,超过上限时,灰度发布将被拦截。

image.png

成功创建多个灰度版本后,您可以在编辑配置面板中看到多个灰度版本以页签的形式展示。

说明

各个灰度版本的展示顺序是根据其优先级来排列的,您可以直观地了解到每个版本的优先级。如果需要调整某个灰度版本的优先级,可以在编辑页面修改相应的优先级数值,并单击发布以生效更改。

image.png

当存在多个并行的灰度版本时,选择其中一个进行全量发布,则该灰度版本的配置将被设为正式版本。一旦正式版本成功发布,所选的那个灰度版本会自动终止;但请注意,其他仍在运行中的灰度版本不会受到影响,这些版本覆盖范围内的节点将继续接收各自对应的灰度配置内容。

多灰度版本优先级

当您的配置有多个灰度版本时,包括正式版本、基于IP的灰度版本以及基于标签的灰度版本(其中基于标签的灰度版本可以有多个),灰度的标签键值对可能匹配到完全不重合的节点列表,也可能匹配到同一个应用节点,Nacos服务端会根据基于IP的灰度版本> 基于标签的灰度版本> 正式版本优先级规则来决定哪个版本将被应用到特定节点上。以下是优先级规则说明:

image.png

  1. 基于IP的灰度版本:如果一个节点同时满足基于IP的灰度条件和其他类型的灰度条件,则该节点将使用基于IP的灰度版本。

  2. 基于标签的灰度版本:对于不适用基于IP灰度规则但符合多个基于标签灰度规则的情况,Nacos会首先查看每个标签灰度版本定义中的priority字段值。priority值越大,优先级越高,priority值相同时,按灰度名称的字符顺序匹配,建议将不同的规则设置为不同的优先级。

  3. 正式版本:只有在没有任何灰度版本适用于当前节点时,才会回退至使用正式版本。

说明

建议:为了确保更精确地控制灰度发布的流程,请尽量为不同目的设置不同的priority值,并合理规划您的灰度策略。这样可以帮助您更加灵活有效地管理配置变更对系统的影响。

相关文档

关于MSE 配置灰度发布的操作步骤,您可参考配置灰度发布