一、前言

实际生产中如有需求变更,并不会直接更新线上服务,最通常的做法便是:切出线上的小部分流量进行体验测试,经过测试后无问题则全面的上线。这样做的好处也是非常明显,一旦出现了BUG,能够保证大部分的客户端正常使用。要实现这种平滑过渡的方式就需要用到本篇文章介绍到的全链路灰度发布

1、什么是灰度发布

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

2、为什么是全链路灰度发布


网关灰度发布实现的是网关通过灰度标记路由到用户服务B(灰度服务),至于从商品服务B到评论服务是通过openFeign内部调用的,默认无法实现灰度标记grayTag的透传,因此用户服务B最终调用的是无法保证调用商品服务的那个,也就是整个链路调用并不全是走灰度服务。

全链路灰度发布需要实现两个点:

  1. 网关路由转发实现灰度发布
  2. 服务内部通过openFeign调用实现灰度发布(透传灰度标记grayTag)。

二、网关层的灰度路由转发

具体实现步骤:

  1. 请求头Header上需有灰度grayTag=true标记
  2. gateway网关层定义全局过滤器,把灰度标记设置到请求头,把grayTag标识放入ThreadLocal
  3. 自定义负载均衡规则,根据grayTag标识调用服务(true调用下游灰度服务,否则相反)
1、自定义全局过滤器

可以参考:gateway定义全局过滤器demo

@Slf4j
@Component
public class GlobalGrayFilter implements GlobalFilter{@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//① 解析请求头,查看是否存在灰度发布的请求头信息,如果存在则将其放置在ThreadLocal中HttpHeaders headers = exchange.getRequest().getHeaders();if (headers.containsKey(GrayConstant.GRAY_HEADER)){String gray = headers.getFirst(GrayConstant.GRAY_HEADER);if (StrUtil.equals(gray,GrayConstant.GRAY_VALUE)){//②设置灰度标记GrayRequestContextHolder.setGrayTag(true);}}//③ 将灰度标记放入请求头中ServerHttpRequest tokenRequest = exchange.getRequest().mutate()//将灰度标记传递过去.header(GrayConstant.GRAY_HEADER,GrayRequestContextHolder.getGrayTag().toString()).build();ServerWebExchange build = exchange.mutate().request(tokenRequest).build();return chain.filter(build);}
}
2、自定义负载均衡策略

具体逻辑:

  1. 获取灰度标记
  2. 从Nacos注册中心获取灰度服务和正常服务
  3. 根据灰度标记去判断,如果灰度发布则选择特定的灰度服务进行转发
*** 灰度发布的规则*/
public class GrayRule extends ZoneAvoidanceRule {@Overridepublic void initWithNiwsConfig(IClientConfig clientConfig) {}@Overridepublic Server choose(Object key) {try {//从ThreadLocal中获取灰度标记boolean grayTag = GrayRequestContextHolder.getGrayTag().get();//获取所有可用服务List<Server> serverList = this.getLoadBalancer().getReachableServers();//灰度发布的服务List<Server> grayServerList = new ArrayList<>();//正常的服务List<Server> normalServerList = new ArrayList<>();for(Server server : serverList) {NacosServer nacosServer = (NacosServer) server;//从nacos中获取元素剧进行匹配if(nacosServer.getMetadata().containsKey(GrayConstant.GRAY_HEADER)&& nacosServer.getMetadata().get(GrayConstant.GRAY_HEADER).equals(GrayConstant.GRAY_VALUE)) {grayServerList.add(server);} else {normalServerList.add(server);}}//如果被标记为灰度发布,则调用灰度发布的服务if(grayTag) {return originChoose(grayServerList,key);} else {return originChoose(normalServerList,key);}} finally {//清除灰度标记GrayRequestContextHolder.remove();}}private Server originChoose(List<Server> noMetaServerList, Object key) {Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(noMetaServerList, key);if (server.isPresent()) {return server.get();} else {return null;}}
}

定义一个配置类,注入改造的灰度策略GrayRule,如下:
注意:这个GrayRuleConfig不能被扫描进入IOC容器,一旦扫描进入则全局生效

*** 灰度部署的负载规则配置类* 注意:这个类一定不要被Spring Boot 扫描进入IOC容器中,一旦扫描进入则对全部的服务都将生效*/
public class GrayRuleConfig {@Beanpublic GrayRule grayRule(){return new GrayRule();}
}

配合@RibbonClients ,可以使单个服务(用户服务)灰度发布

@RibbonClients(value ={//只对用户服务进行灰度发布@RibbonClient(value = "user-server",configuration = GrayRuleConfig.class)
} )
@SpringBootApplication
public class GatewayApplication {}
3、openFeign调用透传灰度标记grayTag
    openFeign在调用时并不是用的原先的Request,而是内部新建了一个Request,其中复制了请求的URL、请求参数一些信息,但是请求头并没有复制过去,因此openFeign调用会丢失请求头中的信息。


因此我们的新建个拦截器,把用户服务请求中的grayTag标识拷贝到openFeign新的request上

@Component
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {HttpServletRequest httpServletRequest = RequestContextUtils.getRequest();Map<String, String> headers = getHeaders(httpServletRequest);for (Map.Entry<String, String> entry : headers.entrySet()) {//② 设置请求头到新的Request中template.header(entry.getKey(), entry.getValue());}}/*** 获取原请求头*/private Map<String, String> getHeaders(HttpServletRequest request) {Map<String, String> map = new LinkedHashMap<>();Enumeration<String> enumeration = request.getHeaderNames();if (enumeration != null) {while (enumeration.hasMoreElements()) {String key = enumeration.nextElement();String value = request.getHeader(key);//将灰度标记的请求头透传给下个服务if (StrUtil.equals(GrayConstant.GRAY_HEADER,key)&&Boolean.TRUE.toString().equals(value)){//① 保存灰度发布的标记GrayRequestContextHolder.setGrayTag(true);map.put(key, value);}}}return map;}
}
4、nacos中配置服务是否是灰度服务

两种方式:
1、在配置文件中指定,如下:

spring:cloud:nacos:discovery:metadata:## 灰度标记grayTag: true

2、在Nacos中动态的指定灰度标记

参考:
https://mp.weixin.qq.com/s/ftoXARaqOmNJVOIsU40myQ
https://www.cnblogs.com/kjcc/p/14378326.html

Spring Cloud全链路灰度发布相关推荐

  1. SpringCloud Nacos 实现全链路灰度发布

    实际生产中如有需求变更,并不会直接更新线上服务,最通常的做法便是:切出线上的小部分流量进行体验测试,经过测试后无问题则全面的上线. 这样做的好处也是非常明显,一旦出现了BUG,能够保证大部分的客户端正 ...

  2. 分布式全链路灰度发布的探索与实践

    简介:在分布式系统中,由于分布式全链路灰度发布因其链路复杂.技术门槛高.落地难度高逐渐成为金融科技实现全链路灰度发布的难点所在.工行在分布式系统建设方面一直走在同业前列,积极探索分布式全链路灰度发布, ...

  3. 工商银行顾欣:分布式全链路灰度发布的探索与实践

    作者|顾欣 互联网金融时代下,金融产品和服务模式不断创新,金融系统容量需求急剧增长,为进一步满足运维标准提升工作的需求,提升服务连续性水平.中国工商银行(后简称工行)从 2014 年开始分布式架构转型 ...

  4. 【305期】Spring Cloud 优雅下线+灰度发布

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每一天进步一点点,是成功的开始... 文章目录 ...

  5. Spring Cloud 优雅下线+灰度发布

    前言 在生产环境中,如何保证在服务升级的时候,不影响用户的体验,这个是一个非常重要的问题.如果在我们升级服务的时候,会造成一段时间内的服务不可用,这就是不够优雅的.那什么是优雅的呢?主要就是指在服务升 ...

  6. 掌门1对1微服务体系Solar第1弹:全链路灰度蓝绿发布智能化实践

    掌门教育自2014年正式转型在线教育以来,秉承"让教育共享智能,让学习高效快乐"的宗旨和愿景,经历云计算.大数据.人工智能.AR/VR/MR以及现今最火的5G,一直坚持用科技赋能教 ...

  7. 服务百万商家的系统,发布风险如何规避?微盟全链路灰度实践

    一分钟精华速览 全链路灰度发布是指在微服务体系架构中,应用的新.旧版本间平滑过渡的一种发布方式.由于微服务之间依赖关系错综复杂,一次发布可能会涉及多个服务升级,所以在发布前进行小规模的生产环境验证,让 ...

  8. 基于 Istio 的全链路灰度方案探索和实践

    作者|曾宇星(宇曾) 审核&校对:曾宇星(宇曾) 编辑&排版:雯燕 背景 微服务软件架构下,业务新功能上线前搭建完整的一套测试系统进行验证是相当费人费时的事,随着所拆分出微服务数量的不 ...

  9. 苏宁金融App全链路灰度实践

    背景 \\ 在这个移动互联网日渐成熟的今天,手机端流量占比高达85%.大家为了抢夺用户手机屏幕上的一席之地,杀成红海,产品的极限飙车.急速迭代.整个系统的日趋复杂可是研发时间一再压缩,变成了移动产品质 ...

最新文章

  1. SQL语句中各个部分的执行顺序(转)
  2. android获得一个view的高度,Android ViewTreeObserver使用总结及获得View高度的几种方法...
  3. Android官方开发文档Training系列课程中文版:打印内容之图像打印
  4. 【codevs1282】约瑟夫问题
  5. 数据库期末总结笔记( 零基础 )--数据库安全性与完整性-范式-E-R图
  6. 我为什么不喜欢网赚和SEO
  7. 虚幻引擎外部模型及动画导入
  8. vue3实现商城左右联动数据---BScroll(vue3代码复制就能用)
  9. php 简繁体,使用php实现简体转繁体的方法
  10. dnf超时空漩涡副本路线流程图_DNF超时空漩涡单人副本怎么入场_超时空漩涡单人副本详细规则 _3DM网游...
  11. Solidworks零件图存放位置更改后装配图识别不出来的解决办法
  12. 线程池的好处,详解,单例(绝对好记)
  13. 如何把自己的电脑配置成外网可访问的服务器?
  14. JAVA学习笔记——集合
  15. 透明质酸仿生细胞纳米囊泡|双载药红细胞膜纳米囊泡|脐带间充质干细胞质膜囊泡
  16. 性能优化(1)-DNS预解析
  17. C语言运算符与表达式课件,C语言课件(运算符和表达式).ppt
  18. YII2.0的I18N/L10N是干什么的?是如何工作的?底层原理是什么?
  19. 怎么在安卓布局里设置滚动字体_最近很火的滚动图标!手机图标随着手势滚动,让你的桌面动起来!...
  20. 图形化开发(一)——Three.js基本介绍-优缺点-在线编辑器 Babylon.JS是最好的JavaScript3D游戏引擎

热门文章

  1. 全球最大同性交友网站GitHub发布了年度开发者报告,提到了这些关键数据
  2. Moonbeam生态说|探索波卡上的LSD
  3. 电商API按图搜索产品(拍立淘),app产品详情原数据,sku详细信息,分类详情,产品详情页面详情
  4. 北大青鸟培训第二周第三天:HTML和CSS相关知识 (持续更新)
  5. 常微分方程王高雄第三版--第一章绪论--Julia实现
  6. caged系统pdf_经度之战.PDF
  7. invariant 释义
  8. 连发10篇SCI!徐州二本学霸全奖直博香港城大引热议,被疑论文「灌水」严重...
  9. SQL中将两个日期进行相减得到分钟或者秒
  10. PyQt 异形Qss