灰度发布(Gray Release,也称为灰度发布或金丝雀发布)是指在软件或服务发布过程中,将新版本的功能或服务以较小的比例引入到生产环境中 , 仅向部分用户或节点提供新功能的一种发布策略 。
在传统的全量发布中,新版本的功能会一次性全部部署到所有的用户或节点上 。然而,这种方式潜在的风险是,如果新版本存在缺陷或问题,可能会对所有用户或节点产生严重的影响 , 导致系统崩溃或服务不可用 。
相比之下 , 灰度发布采用较小的规模,并逐步将新版本的功能引入到生产环境中,仅向一小部分用户或节点提供新功能 。通过持续监测和评估,可以在发现问题时及时回滚或修复 。这种逐步引入新版本的方式可以降低风险,并提高系统的稳定性和可靠性 。
1.实现思路灰色发布的常见实现思路有以下几种:
- 根据用户划分:根据用户标识或用户组进行划分,在整个用户群体中只选择一小部分用户获得新功能 。
- 根据地域划分:在不同地区或不同节点上进行划分 , 在其中的一小部分地区或节点进行新功能的发布 。
- 根据流量划分:根据流量的百分比或请求次数进行划分 , 只将一部分请求流量引导到新功能上 。
2.具体实现Spring Cloud 全链路灰色发布的关键实现思路如下图所示:
文章插图
图片
灰度发布的具体实现步骤如下:
- 前端程序在灰度测试的用户 Header 头中打上标签 , 例如在 Header 中添加“grap-tag: true”,其表示要进行灰常测试(访问灰度服务),而其他则为访问正式服务 。
- 在负载均衡器 Spring Cloud LoadBalancer 中 , 拿到 Header 中的“grap-tag”进行判断,如果此标签不为空,并等于“true”的话,表示要访问灰度发布的服务,否则只访问正式的服务 。
- 在网关 Spring Cloud Gateway 中,将 Header 标签“grap-tag: true”继续往下一个调用服务中传递 。
- 在后续的调用服务中,需要实现以下两个关键功能:
- 在负载均衡器 Spring Cloud LoadBalancer 中,判断灰度发布标签 , 将请求分发到对应服务 。
- 将灰度发布标签(如果存在),继续传递给下一个调用的服务 。
3.核心实现思路和代码灰度发布的关键实现技术和代码如下 。
3.1 区分正式服务和灰度服务在灰度发布的执行流程中,有一个核心的问题,如果在 Spring Cloud LoadBalancer 进行服务调用时,区分正式服务和灰度服务呢?
这个问题的解决方案是:在灰度服务既注册中心的 MetaData(元数据)中标识自己为灰度服务即可,而元数据中没有标识(灰度服务)的则为正式服务,以 Nacos 为例,它的设置如下:
spring:Application:name: canary-user-servicecloud:nacos:discovery:username: nacospassword: nacosserver-addr: localhost:8848namespace: publicregister-enabled: truemetadata: { "grap-tag":"true" } # 标识自己为灰度服务
3.2 负载均衡调用灰度服务Spring Cloud LoadBalancer 判断并调用灰度服务的关键实现代码如下:private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances,Request request) {// 实例为空if (instances.isEmpty()) {if (log.isWarnEnabled()) {log.warn("No servers available for service: " + this.serviceId);}return new EmptyResponse();} else { // 服务不为空RequestDataContext dataContext = (RequestDataContext) request.getContext();HttpHeaders headers = dataContext.getClientRequest().getHeaders();// 判断是否为灰度发布(请求)if (headers.get(GlobalVariables.GRAY_KEY) != null &&headers.get(GlobalVariables.GRAY_KEY).get(0).equals("true")) {// 灰度发布请求,得到新服务实例列表List<ServiceInstance> findInstances = instances.stream().filter(s -> s.getMetadata().get(GlobalVariables.GRAY_KEY) != null &&s.getMetadata().get(GlobalVariables.GRAY_KEY).equals("true")).toList();if (findInstances.size() > 0) { // 存在灰度发布节点instances = findInstances;}} else { // 查询非灰度发布节点// 灰度发布测试请求,得到新服务实例列表instances = instances.stream().filter(s -> s.getMetadata().get(GlobalVariables.GRAY_KEY) == null ||!s.getMetadata().get(GlobalVariables.GRAY_KEY).equals("true")).toList();}// 随机正数值 ++i( & 去负数)int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;// ++i 数值 % 实例数 取模 -> 轮询算法int index = pos % instances.size();// 得到服务实例方法ServiceInstance instance = (ServiceInstance) instances.get(index);return new DefaultResponse(instance);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 如何使用LangChain、RStudio和足够的Python生成人工智能
- 如何收集和准备AI模型的训练数据
- 耳机插进电脑检测到了,但是麦克风没声音,应该如何解决?
- 如何补交养老保险在手机上操作 如何补交养老保险
- 了解手机定位功能,如何不用对方同意查到对方位置
- 微信上,几乎不发朋友圈的男人,并不是低调,多半是这种人
- 微信昵称后面“小耳朵”是干什么用的?我也是刚知道,真的很实用
- 苹果手机微信语音无声音解决攻略
- 微信进一步规范“自媒体”:准确标注信息来源
- 鲜花如何保鲜 花泥鲜花如何保鲜