傻了嘉裤,更新鍵值對(duì)的時(shí)候沒(méi)有把過(guò)期時(shí)間重新設(shè)置回去,導(dǎo)致過(guò)期時(shí)間都被刷新了栖博。具體修改(20行):
redisClient.setAsync(redisKey, data);
改為:
redisClient.setAsync(redisKey, data, 'EX', secondGap);
//--------------------------------20170519更新分割線--------------------------------
線上項(xiàng)目碰到有人惡意發(fā)送廣告消息導(dǎo)流屑宠,并且 APP 本身是不需要好友申請(qǐng)就能發(fā)送消息的,因此需要做一個(gè)簡(jiǎn)單的創(chuàng)建新會(huì)話限制笛匙。
功能比較簡(jiǎn)單明確侨把,但是如果使用普通的數(shù)據(jù)庫(kù),感覺(jué)有點(diǎn)小題大做妹孙。如果單純自己構(gòu)造一個(gè)內(nèi)存數(shù)組又容易丟失數(shù)據(jù)秋柄,所以想到用 Redis 來(lái)做一個(gè)計(jì)數(shù)器。
-
幼年期蠢正,最簡(jiǎn)單的版本是直接使用 Redis 的基礎(chǔ)命令骇笔,用 userId 做 key,直接疊加:
INCR userId
但是這種只能計(jì)算一個(gè)累加和嚣崭,無(wú)法做到按時(shí)間或者按日期這種細(xì)粒度規(guī)則限制笨触。
-
成長(zhǎng)期,利用 expire雹舀,做一個(gè)定時(shí)的策略芦劣。給一個(gè)鍵值對(duì)做一個(gè)超時(shí)時(shí)間(例如一小時(shí)):
SET userId 1 EX 3600
每次申請(qǐng)創(chuàng)建會(huì)話則加一,超過(guò)固定上限就禁止疊加说榆,并且一小時(shí)后計(jì)時(shí)器默認(rèn)歸零虚吟,不需要手動(dòng)再去創(chuàng)建定時(shí)器來(lái)做清零操作。
-
成熟期签财,利用 expire串慰,根據(jù)規(guī)則做一個(gè)數(shù)字編碼,減少 Redis 鍵值創(chuàng)建和刪除的次數(shù)唱蒸,同樣是一個(gè)小時(shí)不能超過(guò)十個(gè)新的會(huì)話邦鲫。
// 是否能創(chuàng)建新的會(huì)話 function canCreateConversation(userId) { var redisKey = userId; // 用userId做 redis 的 key var convsPerHour = 10; // 新會(huì)話的個(gè)數(shù),一小時(shí)限制在十個(gè) var now = new Date(); var hour = now.getHours(); var miniData = hour * 100 + 1; // 當(dāng)前小時(shí)的最小值神汹,每個(gè)小時(shí)數(shù)字不會(huì)超過(guò)10庆捺,所以將小時(shí)數(shù)記在第三位 var maxData = hour * 100 + convsPerHour; // 當(dāng)前小時(shí)的最大值,同上 // 計(jì)算鍵的過(guò)期時(shí)間 var tomorrow = new Date((new Date()).setDate(now.getDate() + 1)).setHours(0, 0, 0, 0); // 明天凌晨 var secondGap = parseInt((tomorrow.getTime() - now.getTime()) / 1000); // 每天十二點(diǎn)刷新數(shù)據(jù)屁魏,方便之后做每天創(chuàng)建會(huì)話數(shù)量的限制疼燥,這里存在一個(gè)時(shí)區(qū)的問(wèn)題 return redisClient.getAsync(redisKey).then(function(data) { if (data) { data = parseInt(data); if (data >= maxData) { // 這個(gè)小時(shí)已經(jīng)超過(guò)最大創(chuàng)建限制了 return Promise.resolve(false); } else { data = data < miniData ? miniData : data + 1; redisClient.setAsync(redisKey, data, 'EX', secondGap); return Promise.resolve(true); } } else { redisClient.setAsync(redisKey, miniData, 'EX', secondGap); return Promise.resolve(true); } }); }
-
完全期,在上面的規(guī)則上蚁堤,加入一個(gè)每天創(chuàng)建新會(huì)話的上限:
也就是數(shù)字編碼的時(shí)候,在表示小時(shí)數(shù)的位之上,再加入一段來(lái)記載每天創(chuàng)建的會(huì)話數(shù)披诗。