咱們知道當網站的訪問量忽然很大的時候確定會對服務器形成影響,甚至沒法訪問,若是是正常的訪問那麼很好說明業務量增大能夠考慮系統的擴展,可是若是是搜索引擎爬蟲頻繁訪問或是一些惡意訪問,那這時候咱們就應該限制這些訪問的訪問次數。redis恰好能夠解決這個問題java
限制每一個用戶每分鐘最多隻能訪問100個頁面。實現思路:key使用有"rate.limiting:IP",value使用數值,用戶每次訪問將value的值經過INCR命令自增1.若是自增後的值是1同時設置過時時間爲1分鐘。這樣用戶每次訪問的時候都讀取該鍵的值,若是超過了100就代表該用戶的訪問頻率超過了限制,須要提示用戶稍後訪問。且該鍵每分鐘會自動被刪除。因此下一分鐘又會從新計算,也就達到了限制訪問頻率的目的。
redis
代碼邏輯:算法
String key = "rage.limiting:"+ip; // 判斷key是否存在 int flag = exists(key);// key rate.limiting:192.168.88.60 if(flag == 1){ // key 存在 自增1 int count = incr(key); if(count > 100){ // 超過限制 log.info("訪問頻率超過了限制,請稍後重試"); return ; } }else{ // key 不存在 multi(); // 開啓事務 incr(key); // key不存在自增1 值爲1 expire(key,60); // 設置過時時間 exec(); // 提交事務 }
實現方式一其實還有個問題,好比若是用戶第一分鐘的訪問了99次,前面58秒訪問了9次,後面1秒訪問了90次,而後用戶後一秒也訪問了99次,然後一分鐘的第一秒訪問了90次,後面的58秒訪問了9次,這樣按照上面的算法是沒有問題的,可是這種極端狀況你們仍是能夠發現問題的。
服務器
解決方法:先將上面案例中的100次調整爲10次便於在次場景中描述,要精確的保證同一個用戶每分鐘最多訪問10次,須要記錄下來用戶每次訪問的時間。所以對每一個用戶咱們使用一個List列表類型的鍵來記錄他最近10次訪問的時間,一旦鍵中的元素超過10個,就判斷最先的元素距離如今的時間是否小於1分鐘。若是是表示用戶最近1分鐘訪問次數超過了10次,若是不是就將如今的時間加入到隊列中,同時把最先的元素刪除。
網站
邏輯代碼搜索引擎
String key = "rate.limiting:"+IP; int listLength = llen(key); if(listLength < 10){ lpush(key,new()); }else{ long time = lindex(key,-1); if(now()-time < 60){ log.info("訪問頻率超過了限制,請稍後再試"); }else{ lpush(key,now); ltrim(key,0,9); } }