SpringCloud实现灰度发布的方法步骤

网友投稿 366 2022-07-28


目录1.什么是灰度发布?2.灰度发布有什么作用?3.灰度发布的实现方式:网关到服务,服务到服务3.1网关到服务代码实现3.2网关到服务代码实现

1.什么是灰度发布?

灰度发布又称金丝雀发布,是在系统升级的时候能够平滑过渡的一种发布方式。在其上可以进行A/B测试,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

关于金丝雀发布名称的来历:矿工下要矿井,要验证是否有瓦斯,金丝雀对瓦斯很敏感,通过观察金丝雀的反应判断是否安全。

2.灰度发布有什么作用?

1.降低发布带来的影响,虽然功能都在测试环境测过,但毕竟没有发布到生产环境,如果先让少部分用户先使用新版本,提前发现bug,或者性能问题,提前做好修复,就可以降低新版本带来的影响;

2.通过对新老版本的对比,观察新版本带来的效果。结合工作中使用到的灰度发布实践和对其他大厂的灰度发布调研,总结了以下灰度发布方案。

3.灰度发布的实现方式:网关到服务,服务到服务

3.1网关到服务代码实现

3.1.1整体流程

指定灰度规则->预制代码规则->springcloud自定义metadata

3.1.2前置环境(需要自行搭建四个至少服务)

eureka:注册中心zuul:网关service-v1:集群服务v1版本service-v2:集群服务v2版本

3.1.3核心代码

pom.xml

io.jmnarloch

ribbon-discovery-filter-spring-cloud-starter

2.1.0

灰度过滤器(核心代码)

@Component

public class GrayFilter extends ZuulFilter {

@Override

public String filterType() {

return FilterConstants.PRE_TYPE;

}

@Override

public int filterOrder() {

return 0;

}

@Override

public boolean shouldFilter() {

return true;//return false 关闭该过滤器

}

@Autowired

private CommonGrayRuleDaoCustom commonGrayRuleDaoCustom;

@Override

public Object run() throws ZuulException {

RequestContext currentContext = RequestContext.getCurrentContext();

HttpServletRequest request = currentContext.getRequest();

String userId = request.getHeader("userId");

// 根据用户id查规则查库,

String rule = findRuleById(userId);

// 金丝雀

if ("v1".equals(rule)) {

RibbonFilterContextHolder.getCurrentContext().add("version", "v1");

// 普通用户

} else if ("v2".equals(rule)) {

RibbonFilterContextHolder.getCurrentContext().add("version", "v2");

}

return null;

}

//查库的伪代码

private String findRuleById(String userId) {

Map map = new HashMap();

map.put("9527", "v1");

map.put("9528", "v2");

return map.get(userId);

}

}

3.2网关到服务代码实现

3.2.1整体流程

springcloud自定义metadata->获取当前用户的版本->遍历服务获取服务的的版本,返回合适的服务

3.2.2前置环境(需要自行搭建5个至少服务)

eureka:注册中心service-A:服务调用方service-v1:集群服务v1版本service-v2:集群服务v2版本

3.2.3核心代码

threadlocal工具类

public class RibbonParameters {

jjOxCLP private static final ThreadLocal local = new ThreadLocal();

public static T get() {

return (T) local.get();

}

public static void set(T t) {

local.set(t);

}

}

切面获取version的值

@Aspect

@Component

public class RequestAspect {

@Pointcut("execution(* com.mashibing.apipassenger.controller..*Controller*.*(..))")

private void anyMehtod() {

}

@Before(value = "anyMehtod()")

public void before(JoinPoint joinPoint) {

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

String version = request.getHeader("version");

//方式二:

HashMap map = new HashMap<>();

map.put("version",version);

RibbonParameters.set(map);

}

rule规则

import com.netflix.client.config.IClientConfig;

import com.netflix.loadbalancer.AbstractLoadBalancerRule;

import com.netflix.loadbalancer.ILoadBalancer;

import com.netflix.loadbalancer.Server;

import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;

import org.springframework.context.annotation.Configuration;

import java.util.List;

import java.util.Map;

@Configuration

public class GrayRule extends AbstractLoadBalancerRule {

@Override

public void initWithNiwsConfig(IClientConfig clientConfig) {

}

@Override

public Server choose(Object key) {

return choose(getLoadBalancer(), key);

}

private Server choose(ILoadBalancer lb, Object key) {

System.out.println("灰度,rule");

Server server = null;

while (server == null) {

List reachableServers = lb.getReachableServers();

//获取当前线程的参数 用户 version=v1

Map map = (Map) RibbonParameters.get();

String version = "";

if (map != null && map.containsKey("version")) {

version = map.get("version");

}

System.out.println("当前rule,version=" + version);

//遍历服务列表选取用户服务

for (int i = 0; i < reachableServers.size(); i++) {

server = reachableServers.get(i);

//用户的version知道了,服务自定义的meta不知道

Map metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();

String metaMap = metadata.get("version");

//用户的version知道了,服务meta也知道了

if (version.trim().equals(metaMap)) {

return server;

}

}

}

return null;

}

}

注意:提前踩坑,No qualifying bean of type ‘com.netflix.loadbalancer.IRule‘ available: expected single matching bean

当是觉得很奇怪,命名自己只定义了grayRule负载均衡策略规则,metadataAwareRule这个我代码中并没有。经过排查自己使用在pom中引入了Ribbon的包,该包默认会带负载均衡策略规则。导致有多个规则,从而报错。

io.jmnarloch

ribbon-discovery-filter-spring-cloud-starter

2.1.0

删除该包即可

删除后重新运行

服务与服务的灰度发布的另外一种方式:可以在requestAspect中获取到version后,直接比对版本:RibbonFilterContextHolder.getCurrentContext().add("version", "v1"),这种凡是与网关与服务的灰度发布相似。

自此灰度发布完成。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springboot vue前后端接口测试树结点添加功能
下一篇:springboot vue接口测试前后端树节点编辑删除功能
相关文章

 发表评论

暂时没有评论,来抢沙发吧~