前后端分离后灰度发布实现方式

1、什么是灰度发布

灰度发布, 也叫金丝雀发布。是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度,而我们平常所说的金丝雀部署也就是灰度发布的一种方式。

2、常见灰度发布策略

策略一:基于客户端公网ip判断是否需要走灰度环境。

策略二:基于用户判断是否走灰度环境。

3、常见实现方式

  对于前后端分离的项目,一般通过nginx 转发解决跨域问题。

3.1 只有服务需要灰度环境

当前端没有修改或者修改不影响逻辑的时候,基本只要控制服务端有灰度环境,这种情况实现如下:

   1、通过nginx+lua+redis,判断是否走灰度环境,其中redis用户存储走灰度环境用,lua在nginx 里面读取用户id,并且获取客户端请求用户id(一般通过请求头获取),通过比较判断,将在reids存储的用户转发到灰度环境网关或者服务端。(注意灰度环境的服务和正式服务注册中心不是同一个或者网络不是同一个)

2、通过服务网关辨别是否转发到灰度服务端。以SpringCloudGateway作为网关框架,nacos作为注册中、为例,具体实现方式:

定义一个灰度标记Holder

public class GrayEnvHolder {

    private static final ThreadLocal<EnvEnum > grayFlag = new ThreadLocal<>();
    public static void setGrayEnvTag(final EnvEnum tag) {
        grayFlag.set(tag);
    }
    public static EnvEnum getGrayEnvTag() {
        return grayFlag.get();
    }
    public static void remove() {
        grayFlag.remove();
    }
}

定义一个过滤器,确认是否要走灰度环境,代码如下

public class GrayGatewayBeforeFilter implements GlobalFilter, Ordered {
    @Autowired
    private GrayGatewayProperties grayGatewayProperties;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        EnvEnum envEnum = EnvEnum.PROD
        // 当灰度开关打开时才进行请求头判断
        if (grayGatewayProperties.getEnabled()) {
          
            // 判断是否需要调用灰度版本
            if (checkGray(exchange.getRequest())) {
                envEnum = EnvEnum.GRAY;
            }
        }
        GrayEnvHolder.setGrayTag(envEnum );
        ServerHttpRequest newRequest = exchange.getRequest().mutate()
                .header(GrayConstant.GRAY_HEADER, grayStatusEnum.getVal())
                .build();
        ServerWebExchange newExchange = exchange.mutate()
                .request(newRequest)
                .build();
        return chain.filter(newExchange);
    }

    /**
     * 校验是否使用灰度版本
     */
    private boolean checkGray(ServerHttpRequest request) {
        if ( checkGrayIPList(request)) {
            return true;
        }
        return false;
    }


    private boolean checkGrayIPList(ServerHttpRequest request) {
        // 读取走灰度环境ip
        List<String> grayIPList = grayGatewayProperties.getGrayIPList();
        if (CollectionUtils.isEmpty(grayIPList)) {
            return false;
        }
        String realIP = request.getHeaders().getFirst("X-Real-IP");
        if (realIP == null || realIP.isEmpty()) {
            realIP = request.getRemoteAddress().getAddress().getHostAddress();
        }
        if (realIP != null && CollectionUtils.contains(grayIPList.iterator(), realIP)) {
            return true;
        }
        return false;
    }

 
    @Override
    public int getOrder() {
        // 设置过滤器的执行顺序,值越小越先执行
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

然后就要通过路由重写,把不同用户转发到不同的环境。我们知道Springboot 项目负载均衡路由有Ribbon实现。它有它默认路由算法。所以我们要重新它即可。此时定义灰度环境版本变为v2:代码如下:

public abstract class AbstractGrayLoadBalancerRule extends AbstractLoadBalancerRule {
    @Autowired
    private GrayVersionProperties grayVersionProperties;

    @Value("${spring.cloud.nacos.discovery.metadata.version}")
    private String metaVersion;

   
    public List<Server> getReachableServers() {
        ILoadBalancer lb = getLoadBalancer();
        if (lb == null) {
            return new ArrayList<>();
        }
        List<Server> reachableServers = lb.getReachableServers();

        return getGrayServers(reachableServers);
    }

    /**
     * 所有已知的服务器,可访问和不可访问,并对灰度标识进行判断
     */
    public List<Server> getAllServers() {
        ILoadBalancer lb = getLoadBalancer();
        if (lb == null) {
            return new ArrayList<>();
        }
        List<Server> allServers = lb.getAllServers();
        return getGrayServers(allServers);
    }

   protected List<Server> getGrayServers(List<Server> servers) {
        List<Server> result = new ArrayList<>();
        if (servers == null) {
            return result;
        }
        String currentVersion = metaVersion;
        EnvEnum envEnum = GrayFlagRequestHolder.getGrayTag();
        if (envEnum != null) {
            switch (envEnum ) {
              case PROD:
                    currentVersion = grayVersionProperties.getProdVersion();
                    break;
                case GRAY:
                    currentVersion = grayVersionProperties.getGrayVersion();
                    break;
            }
        }

        for (Server server : servers) {
            NacosServer nacosServer = (NacosServer) server;
            Map<String, String> metadata = nacosServer.getMetadata();
            String version = metadata.get("version");
            // 判断服务metadata下的version是否于设置的请求版本一致
            // 注意灰度环境和生产正式环境接口版本不一样
            if (version != null && version.equals(currentVersion)) {
                result.add(server);
            }
        }
        return result;
    }
}

网关转发到到灰度环境要移除此线程holder,因此要定义后置拦截器。代码省略。网关转发后就到应用存面,考虑到微服务之间调用,因此要实现灰度标记的传递,通常是通过header传递。

public class GrayFeignRequestInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        // 如果灰度标记存在,将灰度标记通过HttpHeader传递下去
           ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
         String envEnum = request.getHeader("Gray");
        if (envEnum != null ) {
            template.header(envEnum );
        }
    }
}

 当然每个微服务都要重新路由。参数上方的代码即可。方式二灰度环境和正式环境可以部署在同一个网络已经同一个nacos(同一个空间)

3.2 前端和服务端都需要灰度环境

     当前端页面改动也很大时候,或者由于业务需要或者测试需要也要将前端发布灰度环境。首先前端需要打一个灰度环境包

  实现方式如下:

      1 、实现方式 可以参照3.1中方式1,只需要将灰度的前端放指定目录,修改nginx配置即可。

此时服务转发可以直接修改nginx 到网关和微服务转发配置,也可以参照3.1中方式2实现。建议修改nginx配置,这种方式比较简洁、改动比较少

     

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前后端分离项目实现灰度发布的主要思路将前端和后端的发布过程分离,并通过一些技术手段实现部分用户的灰度发布。下面是一种常见的实现方式: 1. 前端部分: - 前端代码可以通过版本控制工具(如Git)进行管理,每个功能或者模块对应一个分支或者一个特定的版本。 - 在灰度发布过程中,可以通过配置文件或者数据库来控制不同用户的访问权重,例如将10%的用户指向新版本,90%的用户指向旧版本。 - 可以使用一些前端框架(如Vue、React等)提供的路由功能,根据用户的访问路径来决定使用新版本还是旧版本。 2. 后端部分: - 后端代码也可以通过版本控制工具进行管理,每个功能或者模块对应一个分支或者一个特定的版本。 - 在灰度发布过程中,可以通过配置文件或者数据库来控制不同用户的访问权重,例如将10%的请求指向新版本,90%的请求指向旧版本。 - 可以使用一些反向代理工具(如Nginx)来实现请求的转发和负载均衡,根据用户的请求路径或者其他标识来决定使用新版本还是旧版本。 3. 监控和回滚: - 在灰度发布过程中,需要对用户的访问情况进行监控和统计,可以使用一些监控工具(如ELK、Prometheus等)来实现。 - 如果发现新版本存在问题或者性能不佳,可以及时回滚到旧版本,保证系统的稳定性和可用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值