欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-02-14 11:20:23
前言  主要针对目前线上短信被脚本恶意盗刷的情况,用redis实现滑动窗口限流public void checkcurrentwindowvalue(string telnum) {...

前言

  主要针对目前线上短信被脚本恶意盗刷的情况,用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滑动窗口限流内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!