openresty实战(四):基于用户uid实现灰度发布

场景

灰度用户uid存储在redis中,灰度用户访问新版本,其他用户访问旧版本。

发布前:需要准备两套环境:灰度环境与生产环境,其中灰度环境集群资源占比为生产环境占比的10%。

发布后:灰度环境保留并接受生产流量,用于下一次灰度环境发布。

核心逻辑:通过用户UID动态路由请求,灰度用户访问新版本服务,其他用户访问旧版本服务。

一、整体业务架构图

二、请求切换流程图

三、OpenResty完整配置

1. Nginx主配置 (nginx.conf)
http {
    # 共享Redis连接配置
    lua_shared_dict redis_conn 10m;
    
    # 灰度服务配置
    upstream old_backend {
        server 10.0.0.1:8080;  # 旧版服务器
        server 10.0.0.2:8080 backup;
    }
    
    upstream new_backend {
        server 10.1.0.1:8080;  # 新版服务器
        server 10.1.0.2:8080 backup;
    }
    
    # Redis配置
    resolver 8.8.8.8;  # DNS解析器
    init_by_lua_block {
        redis_host = "10.2.0.100"  -- Redis IP
        redis_port = 6379
        redis_key = "gray_uids"    -- 存储UID的集合Key
        gray_ratio = 0.1           -- 灰度比例(可选)
    }
    
    server {
        listen 80;
        server_name yourdomain.com;
        
        location / {
            # 执行灰度路由逻辑
            access_by_lua_file /etc/nginx/lua/gray_router.lua;
            proxy_pass http://$backend;  # 动态设置的后端
        }
    }
}
2. Lua路由脚本 (/etc/nginx/lua/gray_router.lua)
-- 获取用户UID (根据实际场景调整)
local function get_uid()
    -- 方案1: 从Header获取
    local uid = ngx.req.get_headers()["X-User-ID"]
    
    -- 方案2: 从Cookie获取
    if not uid or uid == "" then
        local cookie = ngx.var.cookie_userid
        if cookie then uid = cookie end
    end
    
    -- 方案3: 从URL参数获取
    if not uid or uid == "" then
        local args = ngx.req.get_uri_args()
        uid = args["user_id"]
    end
    
    return uid
end

-- Redis查询灰度UID
local function check_gray_uid(uid)
    local redis = require "resty.redis"
    local red = redis:new()
    
    red:set_timeout(1000)  -- 1秒超时
    local ok, err = red:connect(redis_host, redis_port)
    if not ok then
        ngx.log(ngx.ERR, "Redis连接失败: ", err)
        return false
    end
    
    -- 检查UID是否在集合中
    local is_gray, err = red:sismember(redis_key, uid)
    if not is_gray then
        ngx.log(ngx.ERR, "Redis查询失败: ", err)
        return false
    end
    
    -- 放回连接池
    red:set_keepalive(10000, 100)
    return is_gray == 1
end

-- 主路由逻辑
local uid = get_uid()
if not uid then
    ngx.var.backend = "old_backend"  -- 默认旧版
    return
end

-- 检查灰度状态 (带降级保护)
local is_gray = false
local status, ret = pcall(check_gray_uid, uid)
if status and ret then
    is_gray = ret
else
    ngx.log(ngx.ERR, "灰度检查异常: ", ret)
end

-- 设置代理后端
if is_gray then
    ngx.var.backend = "new_backend"
    ngx.log(ngx.INFO, "灰度路由 UID=", uid, " -> 新版本")
else
    ngx.var.backend = "old_backend"
    ngx.log(ngx.INFO, "常规路由 UID=", uid, " -> 旧版本")
end

四、关键组件说明

组件作用示例
Redis存储灰度用户UID集合SADD gray_uids "user1001"
管理后台动态管理灰度UID添加/删除灰度用户
OpenResty请求路由网关执行Lua路由逻辑
旧版本后端稳定版服务v1.0服务集群
新版本后端待发布的新版服务v2.0服务集群

五、灰度发布流程

1、准备阶段

  • 部署新旧版本服务集群

  • Redis创建灰度UID集合(gray_uids

  • 管理后台录入首批灰度用户UID

2、请求处理阶段

3、监控与调整

  • 监控新版本错误率/性能指标

  • 通过管理后台动态调整灰度用户:

    # 添加灰度用户
    redis-cli SADD gray_uids "user2024"
    
    # 移除灰度用户
    redis-cli SREM gray_uids "user1012"

4、全量发布

  • 当新版本稳定后:

    • 修改OpenResty默认路由到新版本

    • 下线旧版本服务

    • 清理Redis灰度配置

六、注意事项

1、UID获取方式

  • 根据业务场景选择:Header > Cookie > URL参数

  • 重要:需确保前端传递UID(移动端/Web端需集成)

2、降级策略

  • Redis故障时自动降级到旧版本

  • UID解析失败时默认走旧版本

3、性能优化

-- 在http块添加
lua_shared_dict gray_cache 50m;  -- 灰度UID本地缓存

-- 在check_gray_uid函数中添加缓存逻辑
local cache = ngx.shared.gray_cache
local cache_key = "gray_" .. uid
local cached = cache:get(cache_key)
if cached ~= nil then
    return cached == 1
end

4、灰度扩展

  • 比例灰度:在Lua脚本中添加随机比例逻辑

  • 多维灰度:结合设备类型/地域等更多维度

实际部署时需:

  1. 调整Redis连接参数(密码/TLS)

  2. 配置Nginx日志记录路由轨迹

  3. 添加Prometheus监控指标

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

alden_ygq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值