網(wǎng)站首頁 編程語言 正文
基于Redis?zSet實(shí)現(xiàn)滑動(dòng)窗口對短信進(jìn)行防刷限流的問題_Redis
作者:聽風(fēng)是雨 ? 更新時(shí)間: 2022-04-15 編程語言前言
主要針對目前線上短信被腳本惡意盜刷的情況,用Redis實(shí)現(xiàn)滑動(dòng)窗口限流
public void checkCurrentWindowValue(String telNum) { String windowKey = CommonConstant.getNnSmsWindowKey(telNum); //獲取當(dāng)前時(shí)間戳 long currentTime = System.currentTimeMillis(); //1小時(shí),默認(rèn)只能發(fā)5次,參數(shù)smsWindowMax做成可配置項(xiàng),配置到Nacos配置中心,可以動(dòng)態(tài)調(diào)整 if (RedisUtil.hasKey(windowKey)) { //參數(shù)smsWindowTime表示限制的窗口時(shí)間 //這里獲取當(dāng)前時(shí)間與限制窗口時(shí)間之間的短信發(fā)送次數(shù) Optional<Long> optional = Optional.ofNullable(RedisUtil.zCount(windowKey, currentTime - smsWindowTime, currentTime)); if (optional.isPresent()) { long count = optional.get(); if (count >= smsWindowMax) { log.error("==========>當(dāng)前號(hào)碼:{} 短信發(fā)送太頻繁,{}", telNum, count); throw new ServiceException(MidRetCode.umid_10060); } } } StringBuilder sb =new StringBuilder(); String windowEle = sb.append(telNum).append(":").append(currentTime).toString(); //添加當(dāng)前發(fā)送元素到zSet中(由于保證元素唯一,這里將元素加上了當(dāng)前時(shí)間戳) RedisUtil.zAdd(windowKey, windowEle, currentTime); //設(shè)置2倍窗口Key:windowKey 的過期時(shí)間 RedisUtil.expire(windowKey, smsWindowTime*2, TimeUnit.MILLISECONDS); }
補(bǔ)充:下面看下以php語言為例基于redis實(shí)現(xiàn)滑動(dòng)窗口式的短信發(fā)送接口限流
滑動(dòng)窗口短信發(fā)送限流算法
1.有兩條規(guī)則
基于IP的限制和基于手機(jī)號(hào)的限制
IP規(guī)則:
1分鐘限制5
10分鐘限制30
1小時(shí)限制50
手機(jī)號(hào)規(guī)則:
1分鐘限制1
10分鐘限制5
1小時(shí)限制10
2.滑動(dòng)窗口就是隨著時(shí)間的流動(dòng) , 進(jìn)行動(dòng)態(tài)的刪減區(qū)間內(nèi)的數(shù)據(jù) , 限制時(shí)獲取區(qū)間內(nèi)的數(shù)據(jù)
最主要的是用到了redis的zRemRangeByScore來進(jìn)行刪除區(qū)間外的數(shù)據(jù)
<?php /*滑動(dòng)窗口短信發(fā)送限流算法 1.有兩條規(guī)則 基于IP的限制和基于手機(jī)號(hào)的限制 IP規(guī)則: 1分鐘限制5 10分鐘限制30 1小時(shí)限制50 手機(jī)號(hào)規(guī)則: 1分鐘限制1 10分鐘限制5 1小時(shí)限制10 */ //IP規(guī)則 $ipRules=array( 60=>5, 600=>30, 3600=>50 ); //手機(jī)號(hào)規(guī)則 $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);//移除窗口以外的數(shù)據(jù) $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; }
原文鏈接:https://www.cnblogs.com/july-sunny/p/15874026.html
相關(guān)推薦
- 2022-03-27 C#?Razor語法規(guī)則_C#教程
- 2023-03-21 通俗易懂的C語言快速排序和歸并排序的時(shí)間復(fù)雜度分析_C 語言
- 2022-03-30 帶你了解Python妙開根號(hào)的三種方式_python
- 2023-02-06 Go語言基礎(chǔ)學(xué)習(xí)之?dāng)?shù)組的使用詳解_Golang
- 2023-01-07 Android?RecyclerBarChart繪制使用教程_Android
- 2022-12-21 React?中的重新渲染類組件及函數(shù)組件_React
- 2022-06-07 使用Docker創(chuàng)建FTP服務(wù)器的過程解析_docker
- 2022-10-01 Qt+FFMPEG實(shí)現(xiàn)循環(huán)解碼詳解_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支