用户维度的灰度方案

背景

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

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

整体流程

简单的流程如下:

处理逻辑:

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

灰度配置规则的存储

  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 均可配置多条规则,只要满足其中任一规则,即视为通过灰度校验。

总结

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

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

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

相关推荐
开心猴爷17 分钟前
iOS App 性能测试中常被忽略的运行期问题
后端
SHERlocked9335 分钟前
摄像头 RTSP 流视频多路实时监控解决方案实践
c++·后端·音视频开发
AutoMQ1 小时前
How does AutoMQ implement a sub-10ms latency Diskless Kafka?
后端·架构
Rover.x1 小时前
Netty基于SpringBoot实现WebSocket
spring boot·后端·websocket
疯狂的程序猴1 小时前
用 HBuilder 上架 iOS 应用时如何管理Bundle ID、证书与描述文件
后端
ShaneD7712 小时前
Redis 实战:从零手写分布式锁(误删问题与 Lua 脚本优化)
后端
我命由我123452 小时前
Python Flask 开发问题:ImportError: cannot import name ‘Markup‘ from ‘flask‘
开发语言·后端·python·学习·flask·学习方法·python3.11
無量2 小时前
Java并发编程基础:从线程到锁
后端
小信啊啊2 小时前
Go语言数组与切片的区别
开发语言·后端·golang
计算机学姐2 小时前
基于php的摄影网站系统
开发语言·vue.js·后端·mysql·php·phpstorm