新聞中心
基于Redis的窗口過(guò)濾策略

目前創(chuàng)新互聯(lián)建站已為上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)頁(yè)空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、雞西梨樹(shù)網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
Redis是一個(gè)開(kāi)源的內(nèi)存數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),它支持各種數(shù)據(jù)結(jié)構(gòu),如字符串、哈希表、列表等,還能夠支持事務(wù)、Lua腳本、持久化,以及分布式集群。在實(shí)際開(kāi)發(fā)中,我們可能會(huì)碰到一些需要實(shí)時(shí)過(guò)濾的數(shù)據(jù),如短信驗(yàn)證碼、異常請(qǐng)求、頻繁操作等。這時(shí),可以采用窗口過(guò)濾策略,即按照一定時(shí)間和數(shù)量來(lái)控制數(shù)據(jù)的進(jìn)出。本文將介紹基于Redis的窗口過(guò)濾策略的實(shí)現(xiàn)方式。
1. Redis的zset結(jié)構(gòu)
Redis的zset結(jié)構(gòu)是一種有序集合,集合中的元素由分值和成員兩部分組成。我們可以使用zadd命令向zset中添加元素,zrange命令來(lái)查詢?cè)?,還可以通過(guò)zrange命令指定score的范圍查詢?cè)亍O旅嫜菔疽幌绿砑釉亍⒉樵冊(cè)?、查詢score范圍內(nèi)的元素的操作。
“`shell
# 添加元素,score為當(dāng)前時(shí)間戳
> zadd myset $(date +%s) “foo”
(integer) 1
# 查詢?cè)?/p>
> zrange myset 0 -1
1) “foo”
# 查詢score范圍內(nèi)的元素
> zrangebyscore myset $(date +%s) -1
1) “foo”
2. 窗口過(guò)濾策略
窗口過(guò)濾策略的基本思路是,維護(hù)一個(gè)有序集合,每個(gè)元素包含時(shí)間戳和唯一標(biāo)識(shí),每當(dāng)有數(shù)據(jù)進(jìn)來(lái)時(shí),先將其加入有序集合,再判斷其在集合中的位置和數(shù)量,如果超過(guò)了規(guī)定的范圍,則將最早的數(shù)據(jù)刪除。下面是一組根據(jù)時(shí)間戳和唯一標(biāo)識(shí)來(lái)過(guò)濾的示例代碼。
```python
import time
class Window(object):
def __init__(self, max_count, max_time):
self.max_count = max_count
self.max_time = max_time
self.redis = redis.Redis.from_url(os.environ["REDIS_URL"])
def push(self, key):
timestamp = time.time()
values = self.redis.zrangebyscore(key, timestamp-self.max_time, timestamp)
if len(values) >= self.max_count:
self.redis.zremrangebyrank(key, 0, len(values)-self.max_count)
return False
else:
self.redis.zadd(key, timestamp, timestamp)
return True
上述代碼中,我們定義了一個(gè)窗口類,初始化時(shí)需要設(shè)定最大數(shù)量和最大時(shí)間。在push方法中,首先獲取當(dāng)前時(shí)間戳,然后使用zrangebyscore方法獲取當(dāng)前時(shí)段內(nèi)的數(shù)據(jù)列表,然后再判斷數(shù)據(jù)列表的數(shù)量是否超過(guò)最大值,超過(guò)則利用zremrangebyrank方法刪除最早的數(shù)據(jù),否則利用zadd方法繼續(xù)添加當(dāng)前數(shù)據(jù)。最后返回True或False表示是否添加成功。
3. 示例應(yīng)用:限制短信驗(yàn)證碼發(fā)送頻率
下面假設(shè)我們有一個(gè)用戶注冊(cè)功能,在注冊(cè)時(shí)需要手機(jī)短信通知驗(yàn)證碼,為了避免用戶重復(fù)注冊(cè)或釣魚(yú)攻擊,我們可以在后端代碼中使用窗口過(guò)濾策略來(lái)限制短信驗(yàn)證碼的發(fā)送頻率。下面是示例代碼:
“`python
import os
import redis
import time
class SmsService(object):
def __init__(self):
self.window = Window(3, 60) # 最大3次/分鐘
self.redis = redis.Redis.from_url(os.environ[“REDIS_URL”])
def send(self, phone):
# 檢查窗口
key = f”sms:{phone}”
if not self.window.push(key):
return False
# 生成驗(yàn)證碼
code = random.randint(1000, 9999)
# 保存驗(yàn)證碼
self.redis.set(key, code)
self.redis.expire(key, 300) # 5分鐘有效期
# 發(fā)送消息
send_sms(phone, f”您的驗(yàn)證碼是{code},5分鐘內(nèi)有效?!?
return True
上述代碼中,我們定義了一個(gè)短信服務(wù)類SmsService,初始化時(shí)創(chuàng)建了一個(gè)窗口實(shí)例和一個(gè)Redis連接。在send方法中,首先調(diào)用窗口實(shí)例的push方法判斷是否需要限制,如果需要,則直接返回False表示無(wú)法發(fā)送短信;否則,根據(jù)傳入的phone生成一個(gè)redis鍵名,生成一個(gè)4位隨機(jī)數(shù)字作為驗(yàn)證碼,保存到Redis中,并設(shè)置5分鐘的有效期,最后調(diào)用send_sms方法發(fā)送短信,并返回True表示發(fā)送成功。
4. 總結(jié)
本文介紹了基于Redis的窗口過(guò)濾策略及其應(yīng)用,展示了窗口類和短信服務(wù)類的示例代碼,以及相關(guān)Redis命令的使用方法。在實(shí)際場(chǎng)景中,我們還可以結(jié)合其他數(shù)據(jù)結(jié)構(gòu)和算法,如Bloom Filter和Spark Streaming等,來(lái)實(shí)現(xiàn)更復(fù)雜的過(guò)濾和分析功能。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開(kāi)通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過(guò)10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開(kāi)發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊(cè)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
網(wǎng)頁(yè)名稱:基于Redis的窗口過(guò)濾策略(redis窗口過(guò)濾)
轉(zhuǎn)載來(lái)于:http://m.fisionsoft.com.cn/article/djjsggc.html


咨詢
建站咨詢
