APP下载

Spring微服务灰度释出(热部署)的实现(二)

消息来源:baojiabao.com 作者: 发布时间:2024-05-15

报价宝综合消息Spring微服务灰度释出(热部署)的实现(二)

接着上篇说,我们微服务中用到的nepxion discovery主要采用了三种灰度释出方式,一种是web图形化界面释出,二是zuul过滤器灰度释出,三是业务引数策略灰度释出。下面将重点介绍三种方式的实现。

一、web图形化界面灰度释出

因为我们专案用到了eureka注册中心,所以选择web图形化界面灰度释出比较合适。

1) 首先需要建立一个discovery控制台工程console, 埠为2222,控制台工程负责web图形化界面请求的处理,执行console工程。

2) 下载discovery ui,地址:https://github.com/Nepxion/DiscoveryUI,执行discovery UI,埠为8090

3)浏览器中输入localhost:8090,即可开启控制台,如下

登陆页面

服务拓扑图

注意:全链路灰度释出需要在“配置中心”下才可用。灰度释出配置中心,负责储存全链路灰度释出规则,并将规则推送到各个微服务中。而配置中心可用nacos,redis等,Discovery 中提供了相应配置中心的外挂包。

二、zuul闸道器过滤器灰度释出

通过闸道器过滤器传递Http Header的方式传递全链路灰度路由规则。下面程式码只适用于Zuul和Spring Cloud Gateway闸道器,Service微服务不需要加该方式。

/ 适用于A/B Testing或者更根据某业务引数决定灰度路由路径。可以结合配置中心分别配置A/B两条路径,可以动态改变并通知

// 当Header中传来的使用者为张三,执行一条路由路径;为李四,执行另一条路由路径

public class MyRouteFilter extends DefaultZuulStrategyRouteFilter {

private static final String DEFAULT_A_ROUTE_VERSION = "{"discovery-gray-service-a":"1.0", "discovery-gray-service-b":"1.1"}";

private static final String DEFAULT_B_ROUTE_VERSION = "{"discovery-gray-service-a":"1.1", "discovery-gray-service-b":"1.0"}";

@Value("${a.route.version:" + DEFAULT_A_ROUTE_VERSION + "}")

private String aRouteVersion;

@Value("${b.route.version:" + DEFAULT_B_ROUTE_VERSION + "}")

private String bRouteVersion;

@Override

public String getRouteVersion() {

String user = strategyContextHolder.getHeader("user");

if (StringUtils.equals(user, "zhangsan")) {

return aRouteVersion;

} else if (StringUtils.equals(user, "lisi")) {

return bRouteVersion;

}

return super.getRouteVersion();

}

}

三、业务引数在策略类中自定义灰度路由规则

通过策略方式自定义灰度路由规则。下面程式码既适用于Zuul和Spring Cloud Gateway闸道器,也适用于Service微服务,同时全链路中闸道器和服务都必须加该方式

// 实现了组合策略,版本路由策略+区域路由策略+IP和埠路由策略+自定义策略

public class DiscoveryGrayEnabledStrategy extends AbstractDiscoveryEnabledStrategy {

private static final Logger LOG = LoggerFactory.getLogger(DiscoveryGrayEnabledStrategy.class);

@Override

public boolean apply(Server server) {

// 对Rest呼叫传来的Header引数(例如:mobile)做策略

String mobile = strategyContextHolder.getHeader("mobile");

String serviceId = pluginAdapter.getServerServiceId(server);

String version = pluginAdapter.getServerMetadata(server).get(DiscoveryConstant.VERSION);

LOG.info("负载均衡使用者定制触发:mobile={}, serviceId={}, version={}", mobile, serviceId, version);

if (StringUtils.isNotEmpty(mobile)) {

// 手机号以移动138开头,路由到1.0版本的服务上

if (mobile.startsWith("138") && StringUtils.equals(version, "1.0")) {

return true;

// 手机号以联通133开头,路由到2.0版本的服务上

} else if (mobile.startsWith("133") && StringUtils.equals(version, "1.1")) {

return true;

} else {

// 其它情况,直接拒绝请求

return false;

}

}

return true;

}

}

上面说了具体灰度规则释出方式,那究竟怎么定义灰度规则呢??

规则是基于XML或者Json为配置方式,储存于本地档案或者远端配置中心,可以通过远端配置中心修改的方式达到规则动态化。其核心程式码参考discovery-plugin-framework以及它的扩充套件、discovery-plugin-config-center以及它的扩充套件和discovery-plugin-admin-center等,规则示例

XML示例(Json示例见discovery-springcloud-example-service下的rule.json)

黑/白名单的IP地址注册的过滤规则

微服务启动的时候,禁止指定的IP地址注册到服务注册发现中心。支援黑/白名单,白名单表示只允许指定IP地址字首注册,黑名单表示不允许指定IP地址字首注册。规则如何使用,见示例说明

全域性过滤,指注册到服务注册发现中心的所有微服务,只有IP地址包含在全域性过滤字段的字首中,都允许注册(对于白名单而言),或者不允许注册(对于黑名单而言)区域性过滤,指专门针对某个微服务而言,那么真正的过滤条件是全域性过滤+区域性过滤结合在一起最大注册数的限制的过滤规则

微服务启动的时候,一旦微服务丛集下注册的例项数目已经达到上限(可配置),将禁止后续的微服务进行注册。规则如何使用,见示例说明

全域性配置值,只下面配置所有的微服务丛集,最多能注册多少个区域性配置值,指专门针对某个微服务而言,那么该值如存在,全域性配置值失效黑/白名单的IP地址发现的过滤规则

微服务启动的时候,禁止指定的IP地址被服务发现。它使用的方式和“黑/白名单的IP地址注册的过滤规则”一致

版本访问的灰度释出规则

1. 标准配置,举例如下

表示消费端1.0版本,允许访问提供端1.0和1.1版本

2. 版本值不配置,举例如下

表示消费端任何版本,允许访问提供端1.0和1.1版本

表示消费端1.0版本,允许访问提供端任何版本

表示消费端任何版本,允许访问提供端任何版本

3. 版本值空字串,举例如下

表示消费端任何版本,允许访问提供端1.0和1.1版本

表示消费端1.0版本,允许访问提供端任何版本

表示消费端任何版本,允许访问提供端任何版本

4. 版本对应关系未定义,预设消费端任何版本,允许访问提供端任何版本

特殊情况处理,在使用上需要极力避免该情况发生

1. 消费端的application.properties未定义版本号,则该消费端可以访问提供端任何版本

2. 提供端的application.properties未定义版本号,当消费端在xml里不做任何版本配置,才可以访问该提供端

版本权重的灰度释出规则

1. 标准配置,举例如下

表示消费端访问提供端的时候,提供端的1.0版本提供90%的权重流量,1.1版本提供10%的权重流量

表示所有消费端访问提供端的时候,提供端的1.0版本提供90%的权重流量,1.1版本提供10%的权重流量

2. 区域性配置,即指定consumer-service-name,专门为该消费端配置权重。全域性配置,即不指定consumer-service-name,为所有消费端配置相同情形的权重。当局部配置和全域性配置同时存在的时候,以区域性配置优先

3. 尽量为线上所有版本都赋予权重值

全域性版本权重的灰度释出规则

1. 标准配置,举例如下

表示版本为1.0的服务提供85%的权重流量,版本为1.1的服务提供15%的权重流量

2. 全域性版本权重可以切换整条呼叫链的权重配比

3. 尽量为线上所有版本都赋予权重值

区域权重的灰度释出规则

1. 标准配置,举例如下

表示消费端访问提供端的时候,区域为dev的服务提供85%的权重流量,区域为qa的服务提供15%的权重流量

表示所有消费端访问提供端的时候,区域为dev的服务提供85%的权重流量,区域为qa的服务提供15%的权重流量

2. 区域性配置,即指定consumer-service-name,专门为该消费端配置权重。全域性配置,即不指定consumer-service-name,为所有消费端配置相同情形的权重。当局部配置和全域性配置同时存在的时候,以区域性配置优先

3. 尽量为线上所有版本都赋予权重值

全域性区域权重的灰度释出规则

1. 标准配置,举例如下

表示区域为dev的服务提供85%的权重流量,区域为qa的服务提供15%的权重流量

2. 全域性区域权重可以切换整条呼叫链的权重配比

3. 尽量为线上所有区域都赋予权重值

闸道器端全链路路由策略的灰度释出规则

1. 标准配置,举例如下

{"discovery-springcloud-example-a":"1.0", "discovery-springcloud-example-b":"1.0", "discovery-springcloud-example-c":"1.0;1.2"}

{"discovery-springcloud-example-a":"qa;dev", "discovery-springcloud-example-b":"dev", "discovery-springcloud-example-c":"qa"}

{"discovery-springcloud-example-a":"192.168.43.101:1100", "discovery-springcloud-example-b":"192.168.43.101:1201", "discovery-springcloud-example-c":"192.168.43.101:1300"}

{"discovery-springcloud-example-a":"1.0=90;1.1=10", "discovery-springcloud-example-b":"1.0=90;1.1=10", "discovery-springcloud-example-c":"1.0=90;1.1=10"}

{"discovery-springcloud-example-a":"dev=85;qa=15", "discovery-springcloud-example-b":"dev=85;qa=15", "discovery-springcloud-example-c":"dev=85;qa=15"}

2. 用法和基于Http Header头部传路由引数一致。前置是通过前端或者闸道器传入,后者是配置在配置档案里。让两者全部启用的时候,以前端或者闸道器传入Header方式优先

注意 路由策略的入口有三个(以{"discovery-springcloud-example-a":"1.0", "discovery-springcloud-example-b":"1.0", "discovery-springcloud-example-c":"1.0;1.2"})为例:

从外界传入(例如:Postman),在Header上加入n-d-version={"discovery-springcloud-example-a":"1.0", "discovery-springcloud-example-b":"1.0", "discovery-springcloud-example-c":"1.0;1.2"}在闸道器Zuul或者Spring Cloud Gateway的Filter中指定闸道器端全链路路由策略的灰度释出规则,在配置中心或者本地rule.xml配置其作用的优先级为外界传入>闸道器Filter指定>配置中心或者本地rule.xml配置

您可以根据自己需求,自由定义灰度释出规则,灵活实现微服务的灰度释出。

源代码位置:https://github.com/Nepxion/Discovery

2019-10-07 17:52:00

相关文章