平台项目迭代发布过程中,有一些功能发布时会产生较大的影响,一旦出现问题,会影响用户使用体验,降低产品信誉。为了解决这一问题,在重要功能发布时需要引入灰度发布功能,借助一小部分用户在生产环境进行功能的验证,平稳运行一段时间,一般是一周后再大规范应用到生产环境的所有用户。
基于nginx+lua(openresty)可以在nginx网关上进行灵活的业务逻辑处理,本文也使用openresty实现。常见的灰度发布是对指定ip网段进行特定的路由处理,但是公司内网的某个网段范围仍然较大,涉及人员较多,本文使用平台管理员(二十多个用户)作为灰度用户,让“自己人”先验证一下重要功能。由于openresty难以获取请求的用户信息,所以需要在header中加入用户信息,仅用在灰度功能,不存在用户信息泄露的安全问题。Openresty实现灰度功能流程图如下图所示:

灰度实现逻辑功能代码如下所示:
upstream portalBackend {server 10.1.1.1:8081;server 10.1.1.2:8081;check interval=3000 rise=2 fall=5 timeout=2000 type=http;check_http_send "HEAD / HTTP/1.0\r\n\r\n";check_http_expect_alive http_2xx http_3xx http_4xx;
}
upstream portalBackendGray {server 10.1.1.3:8081;check interval=3000 rise=2 fall=5 timeout=2000 type=http;check_http_send "HEAD / HTTP/1.0\r\n\r\n";check_http_expect_alive http_2xx http_3xx http_4xx;
}
location ~/api/(.*) {#...............error.log......noticerewrite_log on;#...............account_is_include(userAccount, check_userAccount)#rewrite ^/api/(.*)$ /$1 break;set_by_lua_block $my_ups {function account_is_include(value, tab)local table = json.decode(tab)for k,v in ipairs(table) doif string.lower(v) == string.lower(value) thenreturn trueendendreturn falseendlocal headers = ngx.req.get_headers()local userAccount = headers["grayAccount"]if userAccount == nil thenreturn "portalBackend"endcheck_userAccount = ngx.shared.portalCache:get("userAccountList")if check_userAccount ~= nil and account_is_include(userAccount, check_userAccount) thenlocal key = ngx.shared.portalCache:get("switchKey")if key == "gray" thenreturn "portalBackendGray"else return "portalBackend"endelsereturn "portalBackend"end}proxy_pass http://$my_ups/$1$is_args$args;proxy_redirect off;proxy_set_header Host $host;proxy_set_header X-real-ip $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;#websocketproxy_set_header Origin '';proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "Upgrade";}
最后,介绍一下灰度发布的流程图:















