我们的灰度发布方案

1 背景与解决思路

做灰度发布,主要有两个大的方向

  1. 在代码中做。一套线上环境,代码中做开关,对于不同的用户走不同的逻辑
  2. 在接入层做。多套(隔离的)线上环境,接入层针对不同用户转发到不同的环境中

来分别看下这两种方案的优缺点

方案优点缺点
在代码中做灵活,粒度细;一套代码(环境)运维成本低灰度逻辑侵入代码
在接入层做无需(少)侵入代码;风险小多套线上环境,运维成本高

脱离具体的应用场景谈解决方案都是耍流氓。具体到我们的业务场景:

  1. 对线上的质量要求高,目前无单测,QA黑盒测试,无自动化
  2. 变更周期长(可接受),单次迭代功能点多
  3. 流量低峰期在22点后,整体回归时间长,且存在漏测情况

可以看到我们要做灰度发布的主要诉求是保证线上的质量,尽量降低因迭代带来的服务问题。而非要针对于不同的用户做AB Test。考虑到如果灰度的方案涉及到修改代码,则可能引入其他不确定的风险,在此,我们采用第二种,也就是在接入层做分流的策略。

2 具体实现方案

2.1 接入层 -> Web层

接入层采用nginx,可以基于IP或cookie的方式进行分流,由于我们是商业ERP系统,有用户登录的逻辑,自然选择基于cookie的策略。
就基于cookie的分流策略而言,又有两种实现方案

  1. nginx维护Cookie名单文件,每来一个请求看Cookie是否在名单中,做不同的转发
  2. nginx不维护Cookie名单文件,根据Cookie的特征进行转发

第一种方案的缺点显而易见,每次请求判断是否是灰度用户时间复杂度为O(N);且变更名单,需要操作接入层服务。我们采用第二种方案,具体的实现策略

  1. 业务中维护白名单文件(存放在数据库中)
  2. 在登陆时,如果用户在名单中则给用set特定标识的Cookie;退出或Session过期后Cookie失效
  3. nginx匹配特定Cookie,做转发

这样,调整灰度的范围,只需要操作数据库即可,无需重启服务。

2.2 Web层 -> 核心层模块

目前两层模块之间的解耦方式是通过Zookeeper,对这部分的灰度发布的实现,是通过caller, callee约定一个固定的节点名称(可以把具体的版本号写进去)来实现。

3 运维上的升级

3.1 维护灰度的机器

我们采用${index}.${platform}.${module}来管理模块和机器的对应关系,多了一个灰度的机器,在${platform}中增加一个stage平台名,代表实验环境。

实验环境也属于线上环境,需要增加对应的监控。

全流量的机器不包含实验环境的机器,独立部署,转全后全流量的流量也不会落到stage机器上(nginx的upstream.conf文件不用动)

3.2 建立灰度编译打包、部署任务

全流量的编译打包,和灰度的打出来的包,是一样的,版本号也一样。

只在灰度部署的任务中,自动更新注册节点名称。

由于要固定caller, callee的ZK节点名称,所以,强制在灰度部署任务中,增加一个stage的标记逻辑。

3.3 nginx的转发逻辑

增加对于带cookie的请求转发

location / {
    # ...
    if ($http_cookie ~* "SPECIALID.*|$") {
        proxy_pass http://stage-cluster;
    }

    proxy_pass http://default-cluster;
}
    原文作者:rockops
    原文地址: https://www.jianshu.com/p/eeceac29f390
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞