一種 PHP 版并發(fā)獨占鎖設(shè)計

背景

前段時間有反饋過來說線上有用戶一天會多次簽到吞琐,簽到時間都是同一秒。經(jīng)排查推測是并發(fā)請求一起過來,每個請求都判斷今天未簽到所以都給了放行條件。

所以很有必要加上并發(fā)獨占鎖兴枯。

常規(guī)流程

  1. redis 緩存值,key存在則返回報錯
  2. 文件獨占鎖 flock($file_handle, LOCK_EX)矩欠, 用完釋放

方法有多個結(jié)束出口财剖,需要多處寫釋放代碼。

lock類

把各地方的加鎖癌淮、解鎖抽離出來躺坟,新建lock類。

原理

調(diào)用傳入用戶id乳蓄、鎖名稱咪橙,加鎖方法組裝 redis 緩存 key,

判斷緩存是否存在,不存在則寫入緩存美侦;

存在則進行計數(shù)器增加 incr产舞,并且返回false。

調(diào)用加獨占鎖

//activity.receiveDailyTaskGift
Lock($mid, 'receiveDailyTask')->addUserLock();

釋放獨占鎖

//領(lǐng)取簽到任務(wù)禮金
public function receiveDailyTaskGift($param)
{
    $data = $this->receiveDailyTaskGift($param);
    if ($data['code'] != -1) {
        Lock($param['mid'], 'receiveDailyTask')->clearUserLock();
    }
    return $data;
}

防刷用戶標記(可拓展)

incrLockTimes() 進行計數(shù)器累加音榜,超過了配置中的最大請求數(shù)記錄用戶庞瘸,可列為刷子用戶進行拉黑封號等操作。

實現(xiàn)源碼

/**
 * 用戶獨占鎖
 * created by HongXunPan
 */
class Lock
{
    //一定時間內(nèi)最大請求次數(shù) 超過則列為刷子
    private $maxTimes = 5;

    private $mid;
    private $lockName;
    private $redisKey;

    public function __construct($mid, $lockName = 'lock')
    {
        $this->mid = $mid;
        $this->lockName = $lockName;
        $this->redisKey = $this->lockName .'_'. $this->mid;
    }

    /**
     * 添加用戶獨占鎖
     * @param int $time
     * @return bool|false|int
     */
    public function addUserLock($time = 10)
    {
        if (empty($this->mid)) {
            return false;
        }

        $result = $this->incrLockTimes();
        if ($time != 0 && $result == 1) {
            ocache::redisMember()->expire($this->redisKey, $time);
        }
        return $result;
    }

    /**
     * 清除用戶獨占鎖
     * @return bool|int
     */
    public function clearUserLock()
    {
        if (empty($this->mid)) {
            return false;
        }
        return ocache::redisMember()->delete($this->redisKey);
    }

    /**
     * 一定時間內(nèi)頻繁請求的用戶
     * 超過設(shè)定次數(shù)則特別標記重點觀察
     */
    private function incrLockTimes()
    {
        $times = ocache::redisMember()->incr($this->redisKey);
        if ($times >= $this->maxTimes) {
            //一定時間內(nèi)發(fā)多個請求 超過最大限制
            oo::logs()->dayLog('user lock max time, userId=' . $this->mid . ', key = ' .$this->redisKey . ',times=' . $times, 'lock' . $this->lockName.'txt');
            //todo 封號xxx
        }
        return $times;
    }

    //文件鎖的效率耗時比redis的少,如果不考慮計數(shù)器防刷的情況下優(yōu)先考慮文件鎖
    //-------文件鎖-------

    //文件鎖的弊端是不能設(shè)置過期時間赠叼,不適合做一定時間內(nèi)限制多少次請求以及超出部分怎么處理
    public function addFileLock()
    {
        $lock_path = PATH_DAT . 'lock/';
        $fileName = $lock_path . $this->redisKey;
        $file_handle = fopen($fileName, 'wb+');
        if (flock($file_handle, LOCK_EX)) {
            return true;
        } else {
            return false;
        }
    }

    //todo 需要考慮文件鎖 用完的文件是否需要刪除
    public function clearFileLock()
    {
        $lock_path = PATH_DAT . 'lock/';
        $fileName = $lock_path . $this->redisKey;
        $file_handle = fopen($fileName, 'wb+');
        flock($file_handle, LOCK_UN);
        unlink($fileName);
    }

    //-------文件鎖--------
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末擦囊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嘴办,更是在濱河造成了極大的恐慌瞬场,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涧郊,死亡現(xiàn)場離奇詭異贯被,居然都是意外死亡,警方通過查閱死者的電腦和手機妆艘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門彤灶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人批旺,你說我怎么就攤上這事幌陕。” “怎么了汽煮?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵搏熄,是天一觀的道長。 經(jīng)常有香客問我暇赤,道長心例,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任鞋囊,我火速辦了婚禮止后,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘失暴。我一直安慰自己坯门,他們只是感情好,可當我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布逗扒。 她就那樣靜靜地躺著,像睡著了一般欠橘。 火紅的嫁衣襯著肌膚如雪矩肩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天,我揣著相機與錄音黍檩,去河邊找鬼叉袍。 笑死,一個胖子當著我的面吹牛刽酱,可吹牛的內(nèi)容都是我干的喳逛。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼棵里,長吁一口氣:“原來是場噩夢啊……” “哼润文!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起殿怜,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤典蝌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后头谜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骏掀,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年柱告,在試婚紗的時候發(fā)現(xiàn)自己被綠了截驮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡际度,死狀恐怖葵袭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情甲脏,我是刑警寧澤眶熬,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站块请,受9級特大地震影響娜氏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜墩新,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一贸弥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧海渊,春花似錦绵疲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讯沈,卻和暖如春郁岩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工问慎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留萍摊,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓如叼,卻偏偏與公主長得像冰木,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笼恰,可洞房花燭夜當晚...
    茶點故事閱讀 45,630評論 2 359