php yii Redis實現並發鎖


需要寫一個抽獎活動,並發量很大,抽獎的同時需要操作多個數據表,決定采用redis鎖.

網上找了一下,找到大牛的博客

http://www.cnblogs.com/yjf512/archive/2017/03/22/6597814.html

需要用到lua

Q:很好奇解鎖的函數里為什么要用redis執行lua腳本,為什么不用php直接來操作呢?

A:群里問了下,大概明白了,redis是原子性,操作都是串行,但php是並發操作的,所以在高並發的時候可能存在臟讀的問題,所以使用eval函數在redis里串行的執行這段代碼,因為是串行的,不存在並發問題.

 

Q:如何實現阻塞鎖

A:我沒有在網上找到好的解決方案,都是自己寫循環執行

 

SET key value [EX seconds] [PX milliseconds] [NX|XX]

將字符串值 value 關聯到 key 。

如果 key 已經持有其他值, SET 就覆寫舊值,無視類型。

對於某個原本帶有生存時間(TTL)的鍵來說, 當 SET 命令成功在這個鍵上執行時, 這個鍵原有的 TTL 將被清除。

可選參數

從 Redis 2.6.12 版本開始, SET 命令的行為可以通過一系列參數來修改:

  • EX second :設置鍵的過期時間為 second 秒。 SET key value EX second 效果等同於 SETEX key second value 。
  • PX millisecond :設置鍵的過期時間為 millisecond 毫秒。 SET key value PX millisecond 效果等同於 PSETEX keymillisecond value 。
  • NX :只在鍵不存在時,才對鍵進行設置操作。 SET key value NX 效果等同於 SETNX key value 。
  • XX :只在鍵已經存在時,才對鍵進行設置操作。

因為 SET 命令可以通過參數來實現和 SETNX 、 SETEX 和 PSETEX 三個命令的效果,所以將來的 Redis 版本可能會廢棄並最終移除 SETNX 、 SETEX 和 PSETEX 這三個命令。

 

 1 <?php
 2 /**
 3  * Created by PhpStorm.
 4  * User: yiyz
 5  * Date: 2017/7/6
 6  * Time: 下午2:05
 7  */
 8 
 9 namespace common\vendor;
10 
11 
12 use common\helper\TextHelper;
13 
14 class RedisLock
15 {
16     private $key;
17     private $timeout;
18     private $token;
19 
20     public function __construct($key, $timeout = 10)
21     {
22         $this->key = $key;
23         $this->timeout = $timeout;
24         $this->token = TextHelper::generateOrderNo();
25     }
26 
27     /**
28      * 阻塞加鎖
29      * @return bool
30      */
31     public function lock()
32     {
33         $timeStart = microtime(true) * 1000;
34         while (true) {
35             $res = \Yii::$app->redis->set($this->key, $this->token, "nx", "ex", $this->timeout);
36             if ($res) {
37                 break;
38             }
39             $timeEnd = microtime(true) * 1000;
40             if ($timeEnd - $timeStart > 10000) {
41                 //add log error
42                 return false;43             }
44         }
45         return true;
46     }
47 
48     /**
49      * 解鎖
50      * @return mixed
51      */
52     public function unlock()
53     {
54         $script = '
55         if redis.call("get",KEYS[1]) == ARGV[1]
56         then
57             return redis.call("del",KEYS[1])
58         else
59             return 0
60         end';
61         return \Yii::$app->redis->eval($script, $this->key, $this->token);
62     }
63 }

隨便寫的,沒經過測試,大牛不要笑我...

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM