一种简单实用的灰度切量方案

遇到了一个重要的需求,需要在支付场景上做一个大的改动,改动量较大,虽然已经对技术方案做了很多的review,大量的自测,QA测试,但还是觉得应该逐步放量,如果有问题,及时回切,避免造成过大的影响。
网上搜了一下,方案还是很多的,但是感觉都稍微有点复杂,对于灰度的需求是越简单越好,毕竟主要精力还是在业务逻辑上。最终实现了一版灰度方案,虽然看着简单,但经过生产验证,效果不错,实现了快速切量功能以及部分白名单、黑名单功能,这个涉及支付的需求最终也成功上线。下面把这套方案分享一下。直接上代码了。

public class CallbackGrayRelease extends BaseGrayRelease {
/**
     * 灰度开关,默认打开
     */
    private String open = "true";

    /**
     * 三方白名单,格式:127,119,104。命中该名单的三方订单,走老逻辑
     */
    private String thirdPartnerBlackStr = "";

    /**
     * 灰度白名单,格式:aaa,bbb,ccc。命中该名单的订单,走新逻辑
     */
    private String phoneWhiteStr = "";

    /**
     * 灰度发布的总份数,默认值10000份
     */
    private Integer totalNumber = 10000;

    /**
     * 灰度发布最小比例,totalNumber>= minRate >= 1
     */
    private Integer minRate = 1;

    /**
     * 灰度发布最大比例,,totalNumber>= maxRate >= minRate
     */
    private Integer maxRate = 10000;

    /**
     * 判断是否命中灰度
     */
    public boolean hitGray(String orderId) {
        try {
            if (StringUtils.equals(this.open, "false")) {
                log.info("灰度关闭,orderCode:{}", orderId);
                return false;
            }

            // 判断当前请求是否命中三方黑名单,命中供应商黑名单的走老逻辑
            if (hitThirdPartnerWhiteList(orderId, this.thirdPartnerBlackStr)) {
                return false;
            }

            // 判断当前请求是否命中手机号白名单,命中手机号白名单的走新逻辑
            if (hitPhoneWhiteList(orderId, this.phoneWhiteStr)) {
                return true;
            }
            // 获取订单hash值,判断是否命中灰度
            int hashValue = generateHashByOrderId(orderId, this.totalNumber);
			
			//解释一下minRate和maxRate。minRate是发布最小比例,后者是最大发布比例。比如:minRate是1000,maxRate是5000,那就是只有命中这个范围的hash值才能命中灰度,我们可以自由控制灰度的范围。为什么需要这样实现呢?比如:我们用手机号作为生产hash值的依据,因为每个人的手机号是固定的,就会导致命中灰度和未能命中灰度的人群就定了,实际上我们想要达到的效果是:每次让不同的人群命中灰度
            boolean isHitGray = hashValue >= this.minRate - 1 && hashValue <= this.maxRate - 1;
            log.info("灰度逻辑。当前订单,灰度范围:{},orderCode:{},hashValue:{},isHitGray:{}", String.format("%d ~ %d", this.minRate, this.maxRate), orderId, hashValue, isHitGray);
            return isHitGray;
        } catch (Exception e) {
            log.error("灰度逻辑异常,走老逻辑。orderCode:{},", orderId, e);
            return false;
        }
    }
}

/**
 * 类 描 述:灰度基类
 * 创建时间:2023/6/2 15:22
 * 创 建 人:test
 */
@Component
@Slf4j
public class BaseGrayRelease {
	//hitThirdPartnerWhiteList和hitPhoneWhiteList的方法实现就不贴了
	//就是一个业务黑白名单而已,自己看着实现一下就行了。
	
	//根据订单号生成hash值
    protected int generateHashByOrderId(String orderId,Integer totalNumber) {
        try {
            // & Integer.MAX_VALUE的目的是避免出现负数,一个二进制操作。
            //Integer.MAX_VALUE的十进制是2147483647,对应的二进制是:01111111 11111111 11111111 11111111,首位是0,我们知道二进制的首位是符号位,代表正负,负数的二进制首位是1,正数的二进制首位是0。所以这个与操作会将负数变成正数,保证我们拿到的hash值是一个正数
            return (Objects.hashCode(orderId) & Integer.MAX_VALUE) % totalNumber;
        } catch (Exception e) {
            log.error("灰度逻辑生成订单hash值异常,走老逻辑,orderCode:{}",orderId,e);
            return Integer.MAX_VALUE;
        }
    }
}

以上逻辑,隐藏了业务逻辑,但是主要的技术实现都有了。说明一下,上述代码经过生产验证,是可用的,但是每个业务的情况不一样,不要直接粘代码到生产上使用,而是吸收方案的思想,进而改造成适合自己业务的方案。如果有问题,可以随时留言沟通。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值