Redis實(shí)戰(zhàn)之限制操作頻率

Redis實(shí)戰(zhàn)之限制操作頻率


場(chǎng)景

場(chǎng)景1

留言功能限制染突,30秒內(nèi)只能評(píng)論10次唁情,超出次數(shù)不讓能再評(píng)論啊终,并提示:過于頻繁

場(chǎng)景2

點(diǎn)贊功能限制镜豹,10秒內(nèi)只能點(diǎn)贊10次,超出次數(shù)后不能再點(diǎn)贊蓝牲,并封印1個(gè)小時(shí)趟脂,提示:過于頻繁,被禁止操作1小時(shí)

場(chǎng)景3

上傳記錄功能例衍,需要限制一天只能上傳 100次昔期,超出次數(shù)不讓能再上傳,并提示:超出今日上線

抽離本質(zhì)

在業(yè)務(wù)開發(fā)的過程中佛玄,我們不斷的參與各種業(yè)務(wù)場(chǎng)景的方案設(shè)計(jì)硼一,往往很容易碰到很類似的場(chǎng)景,只不過當(dāng)前所屬的業(yè)務(wù)模塊不一樣梦抢,其實(shí)這些需求的本質(zhì)是解決同一個(gè)問題般贼,當(dāng)我們遇到這種場(chǎng)景的時(shí)候,我們需要根據(jù)自己經(jīng)驗(yàn)分析抽離出需求的本質(zhì)問題奥吩,實(shí)現(xiàn)一個(gè)通用的解決方案哼蛆,這可能就是區(qū)別于你是有靈魂的工程師還是cp(copy paste)最強(qiáng)王者吧。

通過分析上面的需求場(chǎng)景霞赫,其實(shí)他們有很多相似的地方腮介,我們可以把需求場(chǎng)景抽離成:

時(shí)間范圍X秒內(nèi)

限制操作數(shù)Y次

超出封印時(shí)間Z(秒/具體時(shí)間)

超出不讓再操作,并提示

(最小時(shí)間單位用秒:天/小時(shí)/分鐘都可換算成秒端衰,用秒可以解決更多的場(chǎng)景)

如果把功能抽離成一個(gè)通用函數(shù)是不是大概是這樣:

解決方案落地

功能需要進(jìn)行用戶時(shí)間內(nèi)叠洗,操作動(dòng)作,操作次數(shù)存儲(chǔ)旅东,失效過期的清理惕味,這里主角:redis 終于登場(chǎng)了,基于redis特性玉锌,incr的原子操作和key 支持過期機(jī)制名挥,內(nèi)存存儲(chǔ)的效率優(yōu)勢(shì),可以相對(duì)簡(jiǎn)單靈活并且又高效的完成目的主守。

通用功能的代碼實(shí)現(xiàn):


/**

* 頻率限制

* @param string $action 操作動(dòng)作

* @param int $userId 發(fā)起操作的用戶ID

* @param int $time 時(shí)間范圍X秒內(nèi)

* @param int $number 限制操作數(shù)Y次

* @param array $expire? 超出封印時(shí)間Z ['type'=>1,'ttl'=>過期時(shí)間/秒] ['type'=>2,'ttl'=>具體過期時(shí)間戳] 二選一

* @return bool

* @throws \Exception

*/

public function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = [])

{

if (empty($action) || $userId <= 0 || $time <= 0 || $number <= 0) {

throw new \Exception('非法參數(shù)');

}

$key = 'act:limit:' . $action . ':' . $userId;

$r = RedisClient::connect();

//獲取當(dāng)前累計(jì)次數(shù)

$current = intval($r->get($key));

if ($current >= $number) return false;

//累計(jì)并返回最新值

$current = $r->incr($key);

//第一次累加禀倔,設(shè)置控制操作頻率的有效時(shí)間

if ($current === 1) $r->expire($key, $time);

//未超出限制次數(shù)先放過

if ($current < $number) return true;

//超出后根據(jù)需要重新設(shè)置過期失效時(shí)間 $current === $number 判斷保證只重新設(shè)置一次

$type = empty($expire['type']) ? 0 : intval($expire['type']);

$ttl = empty($expire['ttl']) ? 0 : intval($expire['ttl']);

if ($current === $number && $ttl > 0 && in_array($type, [1, 2])) {

if ($type === 1) $r->expire($key, $ttl);

if ($type === 2) $r->expireAt($key, $ttl);

}

return false;

}

//場(chǎng)景1

/**

* 評(píng)論限制

* @param int $userId

* @return bool|string

*/

public function doComment(int $userId)

{

try {

$pass = FrequencyLimit::doHandle('comment', $userId, 30, 10);

if (!$pass) return '過于頻繁';

// todo 評(píng)論邏輯

return true;

} catch (\Exception $e) {

return $e->getMessage();

}

}

//場(chǎng)景2

/**

* 點(diǎn)贊限制

* @param int $userId

* @return bool|string

*/

public function doLike(int $userId)

{

try {

$pass = FrequencyLimit::doHandle('like', $userId, 10, 10, ['type' => 1, 'ttl' => 1 * 60 * 60]);

if (!$pass) return '過于頻繁榄融,被禁止操作1小時(shí)';

// todo 點(diǎn)贊邏輯

return true;

} catch (\Exception $e) {

return $e->getMessage();

}

}

//場(chǎng)景3

/**

* 上傳限制

* @param int $userId

* @return bool|string

*/

public function doUpload(int $userId)

{

try {

$expire = strtotime(date('Y-m-d', strtotime(+1 . 'days')));

$pass = FrequencyLimit::doHandle('upload', $userId, 1 * 24 * 60 * 60, 100, ['type' => 2, 'ttl' => $expire]);

if (!$pass) return '超出今日上線';

// todo 上傳邏輯

return true;

} catch (\Exception $e) {

return $e->getMessage();

}

}


總結(jié)

對(duì)相似的業(yè)務(wù)場(chǎng)景進(jìn)行分析,發(fā)現(xiàn)本質(zhì)問題并設(shè)計(jì)通用的解決方案

基于redis特性救湖,相對(duì)簡(jiǎn)單的實(shí)現(xiàn)通用的頻率限制功能

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末愧杯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鞋既,更是在濱河造成了極大的恐慌力九,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邑闺,死亡現(xiàn)場(chǎng)離奇詭異跌前,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)陡舅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門抵乓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人靶衍,你說我怎么就攤上這事灾炭。” “怎么了颅眶?”我有些...
    開封第一講書人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵蜈出,是天一觀的道長。 經(jīng)常有香客問我涛酗,道長铡原,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任煤杀,我火速辦了婚禮眷蜈,結(jié)果婚禮上沪哺,老公的妹妹穿的比我還像新娘沈自。我一直安慰自己,他們只是感情好辜妓,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開白布枯途。 她就那樣靜靜地躺著,像睡著了一般籍滴。 火紅的嫁衣襯著肌膚如雪酪夷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,043評(píng)論 1 291
  • 那天孽惰,我揣著相機(jī)與錄音晚岭,去河邊找鬼。 笑死勋功,一個(gè)胖子當(dāng)著我的面吹牛坦报,可吹牛的內(nèi)容都是我干的库说。 我是一名探鬼主播,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼片择,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼潜的!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起字管,我...
    開封第一講書人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤啰挪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嘲叔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亡呵,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年借跪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了政己。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掏愁,死狀恐怖歇由,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情果港,我是刑警寧澤沦泌,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站辛掠,受9級(jí)特大地震影響谢谦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萝衩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一回挽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猩谊,春花似錦千劈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至暗甥,卻和暖如春喜滨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撤防。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來泰國打工虽风, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓辜膝,卻偏偏與公主長得像陌凳,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子内舟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • 場(chǎng)景 場(chǎng)景1 留言功能限制合敦,30秒 內(nèi)只能評(píng)論 10次,超出次數(shù)不讓能再評(píng)論验游,并提示:過于頻繁 場(chǎng)景2 點(diǎn)贊功能限...
    java架構(gòu)源閱讀 483評(píng)論 0 0
  • 最近沉迷于業(yè)務(wù)開發(fā)無法自拔 ??充岛,有一段時(shí)間沒有更新博文了,后續(xù)博文內(nèi)容計(jì)劃把一些業(yè)務(wù)場(chǎng)景下的實(shí)戰(zhàn)方案耕蝉,或者比較好的...
    SFLYQ閱讀 547評(píng)論 1 1
  • Lua 5.1 參考手冊(cè) by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,770評(píng)論 0 38
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,448評(píng)論 0 13
  • 從根本上說垒在,決定學(xué)生語文素質(zhì)的不是字詞句的功夫蒜魄,而是思考的欲望和能力。 在語文課堂上對(duì)極少數(shù)非常精辟的字句场躯,我們也...
    qingqianshiguan閱讀 72評(píng)論 0 1