基于Redis zSet实现滑动窗口对短信进行防刷限流的问题

前言

  主要针对目前线上短信被脚本恶意盗刷的情况,用redis实现滑动窗口限流

public void checkcurrentwindowvalue(string telnum) {
        
        string windowkey = commonconstant.getnnsmswindowkey(telnum);
        //获取当前时间戳
        long currenttime = system.currenttimemillis();
        //1小时,默认只能发5次,参数smswindowmax做成可配置项,配置到nacos配置中心,可以动态调整
        if (redisutil.haskey(windowkey)) {
            //参数smswindowtime表示限制的窗口时间
            //这里获取当前时间与限制窗口时间之间的短信发送次数
            optional<long> optional = optional.ofnullable(redisutil.zcount(windowkey, currenttime - smswindowtime, currenttime));
            if (optional.ispresent()) {
                long count = optional.get();
                if (count >= smswindowmax) {
                    log.error("==========>当前号码:{} 短信发送太频繁,{}", telnum, count);
                    throw new serviceexception(midretcode.umid_10060);
                }
            }
        }
        stringbuilder sb =new stringbuilder();
        string windowele = sb.append(telnum).append(":").append(currenttime).tostring();
        //添加当前发送元素到zset中(由于保证元素唯一,这里将元素加上了当前时间戳)
        redisutil.zadd(windowkey, windowele, currenttime);
        //设置2倍窗口key:windowkey 的过期时间
        redisutil.expire(windowkey, smswindowtime*2, timeunit.milliseconds);
    }

补充:下面看下以php语言为例基于redis实现滑动窗口式的短信发送接口限流

滑动窗口短信发送限流算法

1.有两条规则

基于ip的限制和基于手机号的限制

ip规则:

1分钟限制5

10分钟限制30

1小时限制50

手机号规则:

1分钟限制1

10分钟限制5

1小时限制10

2.滑动窗口就是随着时间的流动 , 进行动态的删减区间内的数据 , 限制时获取区间内的数据

最主要的是用到了redis的zremrangebyscore来进行删除区间外的数据

<?php
/*滑动窗口短信发送限流算法
1.有两条规则
 基于ip的限制和基于手机号的限制
 ip规则:

 1分钟限制5
 10分钟限制30
 1小时限制50

 手机号规则:
 1分钟限制1
 10分钟限制5
 1小时限制10
*/
//ip规则
$iprules=array(
    60=>5,
    600=>30,
    3600=>50
);
//手机号规则
$phonerules=array(
    60=>1,
    600=>5,
    3600=>10
);

$r = checklimits($iprules,$_server["remote_addr"],$_get['tel']);
var_dump($r);

$r = checklimits($phonerules,$_get['tel'],$_get['tel']);
var_dump($r);

function checklimits($rules,$key,$tel){
    $redis = new redis();
    $redis->connect('115.159.28.111', 1991);
    foreach($rules as $ruletime=>$rule) {
        $rediskey=$key."_".$ruletime;
        $score=time();
        $member=$tel.'_'.$score;
        $redis->multi();
        $redis->zremrangebyscore($rediskey, 0, $score - $ruletime);//移除窗口以外的数据
        $redis->zadd($rediskey, $score, $member);
        $redis->expire($rediskey, $ruletime);
        $redis->zrange($rediskey, 0, -1, true);
        $members = $redis->exec();
        if (empty($members[3])) {
            break;
        }
        $nums=count($members[3]);
        var_dump($nums);

        if($nums>$rule){
            return false;
        }
    }
    return true;
}

到此这篇关于基于redis zset实现滑动窗口对短信进行防刷限流的文章就介绍到这了,更多相关redis zset滑动窗口限流内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

(0)
上一篇 2022年3月21日
下一篇 2022年3月21日

相关推荐