在實現簡單的介面限流或者商品秒殺時,一般需要redis來作為計數器。但是在併發場景下,使用不當的可能會踩坑。
這裡主要的坑就是:使用不當,會造成key永久有效,永不過期,導致value一直在increment,無法起到限流的作用。
下面就以反面例子說明:
本文使用的是spring-data-redis的redistemplate
org.springframework.boot
spring-boot-starter-data-redis
反面例項
1public
void limit() throws
exception
7if (incrresult > 100)
10 }
這個**的錯誤在第4,5行。
因為redisservice.increment()在key為空的情況下,不是原子性操作。
實際是兩步操作,首先redis 的incr 命令將 key 中儲存的數字值增1;如果 key 不存在,那麼 key 的值會先被初始化為 0 ,然後再執行 incr 操作,且將key的有效時間設定為長期有效。
當計數器設定成功之後,給key加expire時間時出現服務故障,將會導致整個key一直存在。無法起到限流作用
正確寫法1
1public
void limit() throws
exception 8//
防止出現併發操作未設定超時時間的場景,這樣key就是永不過期,存在風險
9if (redisservice.getexpire(rediskey, timeunit.seconds) == -1)
13if (incrresult > 100)
16 } catch
(exception e)
20 }
正確寫法2:給key加乙個時間字尾,這樣即時出現永不過期的key也只影響其中某一時間段內的key
1public
void limit() throws
exception
8if (incrresult > 100)
11 } catch
(exception e)
15 }
Redis 簡單限流
首先我們來看乙個常見 的簡單的限流策略。系統要限定使用者的某個行為在指定的時間裡只能允許發生 n 次,如何使用 redis 的資料結構來實現這個限流的功能?這個限流需求中存在乙個滑動時間視窗,想想 zset 資料結構的 score 值,是不是可以通過 score 來圈出這個時間視窗來。而且我們只需要...
redis簡單限流
需求 如果要保證乙個使用者一分鐘內只能訪問5次介面,超過就拒絕範圍。這個限流需求中存在乙個滑動時間視窗,想想 zset 資料結構的 score 值,是不是可以通過 score 來圈出這個時間視窗來。而且我們只需要保留這個時間視窗,視窗之外的資料都可以砍掉。那這個 zset 的 value 填什麼比較...
使用Redis進行限流
通過使用註解 提供介面形式與引數形式2種方式 針對性的對介面進行限流,底層使用redis配合lua指令碼實現令牌桶。public class redisratelimiter public boolean tryacquire string flag,int maxpermits,int addra...