使用Redis做一個(gè)簡(jiǎn)單的新好友數(shù)量限制規(guī)則

傻了,更新鍵值對(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ù)器。

  1. 幼年期,最簡(jiǎn)單的版本是直接使用 Redis 的基礎(chǔ)命令,用 userId 做 key,直接疊加:

    INCR userId

    但是這種只能計(jì)算一個(gè)累加和,無(wú)法做到按時(shí)間或者按日期這種細(xì)粒度規(guī)則限制。

  2. 成長(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)做清零操作。

  3. 成熟期,利用 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);
            }
        });
    }
    
  4. 完全期,在上面的規(guī)則上,加入一個(gè)每天創(chuàng)建新會(huì)話的上限:

    也就是數(shù)字編碼的時(shí)候,在表示小時(shí)數(shù)的位之上,再加入一段來(lái)記載每天創(chuàng)建的會(huì)話數(shù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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