本系统采用nginx+lua+redis来实现灰度系统的动态路由控制。
1.采集灰度用户放入redis中
2.根据用户的cookie值反解析用户信息和之前存储的目标灰度用户进行对比。如果存在则请求灰度服务,否则请求正常服务。
nginx配置信息:
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
lua_package_path '/webapp/openresty/nginx/conf/?.lua;;';
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream client1 {
server 127.0.0.1:8081 weight=1;
}
upstream client2{
server 127.0.0.1:8082 weight=1;
}
server {
listen 8080;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#前端请求到这里,解析并执行lua脚本
location /hnmccClient {
default_type text/plain;
content_by_lua_file /webapp/nginx/conf/waf/test.lua;
root /;
}
location @client1{
proxy_next_upstream error timeout;
proxy_redirect off;
proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
client_body_buffer_size 256k;
proxy_connect_timeout 180;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_buffer_size 8k;
proxy_buffers 8 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_pass http://client1;
}
location client2{
proxy_next_upstream error timeout;
proxy_redirect off;
proxy_set_header Host $host;
#proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-IP $http_x_forwarded_for;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
client_body_buffer_size 256k;
proxy_connect_timeout 180;
proxy_send_timeout 180;
proxy_read_timeout 180;
proxy_buffer_size 8k;
proxy_buffers 8 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_pass http://client2;
}
具体的lua脚本如下:
local userCookie = ngx.var.cookie_hncmjsSSOCookie
if(userCookie==nil or userCookie=="") then
ngx.exec("@client1")
return
end
local resultCookie = (string.gsub(userCookie,"@hn.ac.10086.cn",""))
if(resultCookie==nil or resultCookie=="") then
ngx.exec("@client1")
return
end
--引入nginx-redis模块
local redis = require "resty.redis"
--初始化redis客户端1
local red = redis:new()
--设置超时时间300ms
red:set_timeout(300)
--建立连接
local ok, err = red:connect("127.0.0.1", 6380)
--如果建立连接失败,则请求正常服务
if not ok then
ngx.exec("@client1")
return
end
--通过cookie获取用户信息
local cookie = (string.gsub(resultCookie,"\"",""))
local userInfo = red:get(cookie)
local foo = require "foo"
local userInfoArr = foo.split(userInfo,"|")
--解析用户信息里面的手机号
local reqMobile = userInfoArr[10]
--如果手机号为空,则请求正常服务
if(reqMobile==nil or reqMobile=="") then
ngx.exec("@client1")
return
end
--初始化redis客户端2
local red2 = redis:new()
--设置超时时间300ms
red2:set_timeout(300)
--建立连接
local ok2, err2 = red2:connect("127.0.0.1", 6380)
--如果建立连接失败,则请求正常服务
if not ok2 then
ngx.exec("@client1")
return
end
--判断当前手机号是否在灰度目标群体中,如果存在,则请求灰度服务,否则请求正常服务
local flag = red2:sismember("AB_TEST",reqMobile)
if(flag == 1) then
ngx.exec("@client2")
return
end
ngx.exec("@client1")
上面用到了一个字符串拆分函数:
local _M = {}
function _M.split(s, delim)
if type(delim) ~= "string" or string.len(delim) <= 0 then
return
end
local start = 1
local t = {}
while true do
local pos = string.find (s, delim, start, true) -- plain find
if not pos then
break
end
table.insert (t, string.sub (s, start, pos - 1))
start = pos + string.len (delim)
end
table.insert (t, string.sub (s, start))
return t
end
return _M