Redis-INCR并发频次验证

背景

后端接口经常会遇到并发验证问题,在一定的时间范围内,接口只能被请求一定的次数,例如:N秒内接口只能被调用M次;这时候可以用读写效率比较强劲的redis进行校验

  • 先考虑普通get,set验证1s只能请求1次情况(对比demo,不推荐)
//1s 1次验证
let check = async (key, time, value) => {
    let result = true
    try {
        let isCheck = await
            redisClient
                .getAsync(key)
        if (isCheck) {
            result = false
        } else {
            await redisClient
                .multi()
                .set(key, value)
                .expire(key, time)
                .execAsync()
        }
    } catch (error) {
        redisClient
            .delAsync(key)
            .catch(err => { console.log(err) });
        console.log(error)
    }
    return result
}
功能逻辑实现了,但是缺陷比较明显,redis的读和写是分两步,非原子性,存在时间差、
在极小的时间片内,会出现验证失效的情况(第一个请求的redis还没有写入完成,第二个请求已经在读取redis数据)
  • INCR 操作

let check = async (key, time,count) => {
    let result = true
    try {
        let value = await redisClient
            .INCRAsync(key)
        if (+value == 1) {
           // 时间设置和incr操作不是事务,没有原子性,所以实际验证的时间比time稍长一点
           await redisClient
                .expireAsync(key, time)
        } else if(+value > count){
            result = false
        }
    } catch (error) {
        // 防止Redis异常,导致验证key长期存在的情况
        // 想要过期时间和incr操作实现原子性,可以考虑用lua脚本实现功能,业务方运行脚本即可
        redisClient
            .delAsync(key)
            .catch(err => { console.log(err) });
        console.log(error)
    }
    return result
}
取值范围:
INCR操作,如果key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行加1的操作,
其它请求执行 INCR 操作会再次增加1,INCR的value有效范围是64位有符号数字(作统计用的时候注意不要越界)

原子性:
INCR也是一种加锁的操作,自身具有原子性,对并发请求有很好的验证,对于 接口限流 和 请求统计 都是个不错的选择
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值