php yii Redis实现并发锁
需要写一个抽奖活动,并发量很大,抽奖的同时需要操作多个数据表,决定采用redis锁.
网上找了一下,找到大牛的博客
http://www.cnblogs.com/yjf512/archive/2017/03/22/6597814.html
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 }
随便写的,没经过测试,大牛不要笑我...