php laravel 搶紅包防止併發(超賣也是同理)

首先要了解的是:1.Redis如何保證原子性?

                              答案很簡單,因爲redis是單線程。

一、看下面代碼(僅僅是看,後面貼的有代碼可複製)

 

分析:通過jmeter併發測試發現仍然出現類似超賣情況,

          上圖中 llen 和 lpush 兩次操作如果單獨執行是具備原子性的,但是這兩個操作組合起來纔算是完成一個業務,那麼這2個命令組合起來就不具備原子性,所有在兩個操作之間其他客戶端會出現髒讀。

 

二、再優化代碼如下:

在後臺設置紅包的時候執行以下操作,

然後用戶領取紅包請求接口的時候只做一步redis操作。

public function getPacket(Request $request) {
        
        $packet_id = $request->input('packet_id',0);
        if(!$packet_id){
            return Response::error('缺少參數:packet_id') ;

        }
        $redisConfig = config('database.redis.default');
        $redis = new Client($redisConfig);
        $count = $redis->lpop('red_packet_id:'.$packet_id);
        if(!$count){
            return Response::error('已經搶光了哦') ;
        }
        return Response::success('恭喜您,搶到了哦!') ;

    }

總結:

        這裏利用 redis 操作的原子性來實現。首先我們把 紅包個數或者庫存 存在“red_packet_id:1”這個列表中,假設id=1的這個紅包的可領取個數爲10個,就往列表中push10個數,這個數沒有實際意義,僅僅只是代表紅包的可被領取次數。搶購或者紅包到開始領取時間後,每到來一個用戶,就從“red_packet_id:1”中 pop 一個數,表示用戶搶購成功。當列表爲空時,表示已經被搶光了。因爲列表的pop操作是原子的,即使有很多用戶同時到達,也是依次執行的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章