![315b8fa4fe59c99de230a8fef2bcf73a.png](https://i-blog.csdnimg.cn/blog_migrate/27c53ba14f442b1ce1cdcc06c509c36f.jpeg)
一、前言
在一般情况下,升级服务器端应用,需要将应用源码或程序包上传到服务器,然后停止掉老版本服务,再启动新版本。但是这种简单的发布方式存在两个问题,一方面,在新版本升级过程中,服务是暂时中断的,另一方面,如果新版本有BUG,升级失败,回滚起来也非常麻烦,容易造成更长时间的服务不可用。
二、Apollo简介
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
三、场景介绍
大致的场景如下,消费端通过gateway访问提供端,提供端为集群部署(A1、A2),我们部署新应用时让所有流量都切换到A1,我们部署A2。当A2部署完成后我们切换部分流量到A2无异常后我们再切换部署A1,这样我们就能实现不停机发布。
![e4876d99a4f9a9a0b02d3dae1caac9ad.png](https://i-blog.csdnimg.cn/blog_migrate/7d4d9b7e371acdf7f676b5f7a869a253.jpeg)
四、实现过程
1.配置提供端eureka元数据:
需要实现灰度发布我们需要用到Eureka注册中心的特性,Eureka的元数据有两种:标准元数据和自定义元数据,这里我们用到了自定义元数据,自定义元数据可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但一般不会改变客户端的行为,除非客户端知道该元数据的含义,例如将提供端集群(A1、A2)分别添加如下配置:
A1:
eureka.instance.metadata-map.group-name=server01
A2:
eureka.instance.metadata-map.group-name=server02
2.Apollo配置中心新增灰度配置:
apollo如何搭建及配置灰度这里就不做介绍官网有详细的文档说明,配置完成后如下图:
![5eb4ecb373d405162c28b116089f02b6.png](https://i-blog.csdnimg.cn/blog_migrate/27507cf46bf24af394fc611339bcfac0.jpeg)
将灰度配置和主配置分别指定集群的不同主机,这样我们的eureka自定义元数据就推送到了相应的服务端。
3.自定义Ribbon规则
在spring cloud Gateway网关中我们自定义Ribbon负载均衡的规则,利用eureka自定义元数据的特性,我们可以在ribbon中获取远程服务的元数据配置,在网关gateway中我们增加如下两项配置:
# 指定当前流量引流的集群名称eureka.instance.metadata-map.group-name=server01#将规则应用到哪些服务eureka.instance.metadata-map.gray-server-name=wxt-k3-provider、wxt-act-provider
通过在apollo上我们可以实现动态的切换,将请求流量转发到group-name指定的集群。
Ribbon自定义配置相关代码如下,主要实现了如下两点:
1.获取远程服务的自定义元数据配置。
2.获取网关自定义灰度规则。
2.远端服务配置与gateway配置比较如果一致将流量发送到对应服务。
public class RibbonFilter extends AbstractLoadBalancerRule {/**服务分组[all,server01,server02]*/@Value("${eureka.instance.metadata-map.group-name}")private String appGroupName;/**灰度服务[all:所有服务,none:不进行灰度,uaf-k3-provider,uaf-intellicredit-provider:指定服务]*/@Value("${eureka.instance.metadata-map.gray-server-name}")private String grayServerName;/**初始随机规则*/Random rand = new Random();@Overridepublic void initWithNiwsConfig(IClientConfig iClientConfig) {}@Overridepublic Server choose(Object o) {/**可用服务*/List upList = getLoadBalancer().getReachableServers();/**所有服务*/List allList = getLoadBalancer().getAllServers();/**服务数*/int serverCount = allList.size();if (serverCount == 0) {return null;}/**服务名称*/String serverName = ((DiscoveryEnabledServer) upList.get(0)).getInstanceInfo().getAppName();/**判定是否进入灰度流程*/if ("all".equalsIgnoreCase(grayServerName) && !appGroupName.equalsIgnoreCase("all")) {return grayStrategy(upList);} else if (grayServerName.toUpperCase().contains(serverName) && !appGroupName.equalsIgnoreCase("all")) {return grayStrategy(upList);} else {int index = this.rand.nextInt(serverCount);return upList.get(index);}}/** * 灰度调用规则 * @param upList eureka可用服务列表 */public Server grayStrategy(List upList) {for (Server server : upList) {/**服务分组*/String upAppGroupName = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata().get("group-name");if (appGroupName.equals(upAppGroupName)) {MySlf4j.textInfo("进入灰度规则,服务地址:{0},集群组:{1}", server.getHost(), upAppGroupName);return server;}}return null;}}
自此我们完成了灰度部署相关的配置,通过分布式配置中心apollo,我们可以实现不停机维护。