用户维度的灰度方案

背景

在日常开发中,当修改了一些核心代码,或遇到测试环境难以完全覆盖的场景时,我们希望在上线时能通过灰度逐步放量来验证新逻辑。这样一来,如果发现问题,也可以快速切换回旧逻辑。

下面我就介绍下,一个简单的基于用户维度的灰度的方式。

整体流程

简单的流程如下:

处理逻辑:

接收到用户请求后,系统会根据用户标识和灰度配置规则进行处理,判断该用户是否被灰度。如果用户被灰度,则执行新的代码逻辑;如果未被灰度,则执行旧的代码逻辑。

灰度配置规则的存储

  1. 配置中心,使用的时候直接读取配置中心的配置,修改灰度的配置的时候,配置中心也可以快速的推到应用中,快速生效配置。
  2. 数据库+缓存,使用的时候从数据库中将配置加载到缓存中,读取缓存的灰度配置的数据,使用数据库+缓存的方式,修改灰度配置的时候要复杂一点,先去修改数据库里面的配置,再去删掉缓存中的数据。

灰度配置规则的处理

灰度配置处理逻辑

java 复制代码
     public boolean isGray(Long userId) {

        if (userId == null) {
            return false;
        }

        try {
		        // 灰度配置规则可以从 apollo 或者从缓存中取,根据实际情况 获取gray_config
            String rule = config.getProperty("gray_config", "");

            if (StringUtils.isEmpty(rule)) {
                return false;
            }

            JSONArray objects = JSON.parseArray(rule);

            if (CollectionUtils.isEmpty(objects)) {
                return false;
            }
            for (Object object : objects) {

                JSONObject jsonObject = (JSONObject) object;
                String type = jsonObject.getString("type");

                if (StringUtils.isEmpty(type)) {
                    continue;
                }

                if ("direct".equals(type)) {
                    String userIds = jsonObject.getString("data");
                    Set<String> userIdSet = StringUtils.commaDelimitedListToSet(userIds);
                    if (userIdSet.contains(String.valueof(userId))) {
                        return true;
                    }
                }

                if ("mod".equals(type)) {
                    Integer scale = jsonObject.getInteger("data");
                    if (scale < 0) {
                        continue;
                    }
                    if (scale >= 100) {
                        return true;
                    }

                    Integer remainder = (int) (userId % 100);
                    if (remainder <= scale) {
                        return true;
                    }
                }

            }
        }
        catch (Exception ex) {
            logger.error("处理灰度失败", ex);
        }
        return false;
    }

用户配置规则gray_config可以如下配置

java 复制代码
[
    {
        "type": "mod",
        "data": "10"
    },
    {
        "type": "direct",
        "data": "10001,10002"
    }
]

上述灰度配置表示的含义如下:

第一个配置:使用用户 ID 与 100(可自定义)取模。当取模后的值大于等于 0 且小于 10 时,表示该用户被灰度。如需扩大灰度范围,可以将 data 值调大,直到大于等于 100 时实现全量放开。当 data 值小于 0(如 -1)时,则为全量关闭。

第二个配置:将用户 ID 与指定的用户 ID 列表进行对比。如果用户 ID 存在于该列表中,则表示该用户被灰度;反之则未被灰度。

mod 和 direct 均可配置多条规则,只要满足其中任一规则,即视为通过灰度校验。

总结

以上介绍了一个简单的用户维度的灰度方案,可以灵活指定用户灰度或者按照比例对用户进行灰度。

这个用户比例计算也是一个大致的范围,可能有数据倾斜,不过总体还是能反应用户的分布的。

最后当灰度完成后,需要将旧代码删除。

相关推荐
我不会起名字322几秒前
seq 空洞排查:Mongo 的 51 只是预留上界,Redis CURR 才是已消耗边界
redis·后端·mongodb·go·即时通讯·im·故障排查
特立独行的猫A1 分钟前
少 3 个环节、少 1 次 ABI、少 3500 行代码:cj-tauri 与 Ionic/Capacitor 的鸿蒙桥接机制对比
java·后端·python
学长毕设16 分钟前
基于SpringBoot的高校后勤报修管理系统-附源码
java·spring boot·后端
特立独行的猫A25 分钟前
cj-tauri vs Rust/Tauri 同款播放器实测:编译 21 秒 vs 11 分钟,磁盘 12 MB vs 1.2 GB
java·后端·python
乐橙开放平台1 小时前
海康和大华摄像头能统一管理吗?可以通过 GB28181 或视频融合平台接入
网络·后端·物联网·音视频
一条Go4 小时前
OnCall 时段路由:跨午夜、左闭右开与「Local 不是时区」
后端·架构·github
Moment4 小时前
不会后期的我,发现了一个开源胶片神器😍😍😍
前端·后端·开源
数据库小学妹4 小时前
pgbouncer 事务池:prepared statement、临时表与会话状态
数据库·后端·postgresql
三小河5 小时前
SWC 凭什么比 Babel 快 ?项目优化迁移踩坑记录
前端·后端
鶴哥只手遮天5 小时前
《Redis 8.10.3 深度剖析》系列 ·第 17 章. 一个迟到十六年的类型
redis·后端·开源