为什么需要加锁?
为了在高并发下能够保持数据的一致性,避免脏数据。在分布式的集群环境中,就需要使用分布式锁来保证不同节点的线程同步执行。
分布式锁的基本条件
为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下几个条件:
1、互斥性。在任意时刻,只有一个客户端能持有锁。
2、不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
3、解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了,即不能误解锁。
 
分布式锁实现
 这里,我们使用Redis SET 命令的 NX 和 EX 参数来实现分布式锁!
参数介绍:
- EX second :设置键的过期时间为 second 秒。
- NX :只在键不存在时,才对键进行设置操作。
 PHP代码实现:
 Lock.php
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 
 | <?php
 
 
 
 
 class Lock
 {
 
 
 
 private $scene;
 
 
 
 
 private $config;
 
 
 
 
 
 private $redis;
 
 
 
 
 private $lockValue;
 
 
 
 
 private $expire = 5;
 
 
 
 
 public function __construct($scene = 'kill', $config = [])
 {
 $this->scene = $scene;
 $this->config = $config ? $config : ['host' => '127.0.0.1', 'port' => 6379];
 $this->redis = $this->connect();
 }
 
 
 
 
 public function connect()
 {
 $redis = new Redis();
 $redis->connect($this->config['host'], $this->config['port']);
 return $redis;
 }
 
 
 
 
 public function lock()
 {
 
 $this->lockValue = md5(uniqid());
 return $this->redis->set($this->scene, $this->lockValue , ['NX', 'EX' => $this->expire]);
 }
 
 
 
 
 public function unLock()
 {
 
 
 $script = <<<LUA
 local key=KEYS[1]
 local value=ARGV[1]
 if(redis.call('get', key) == value)
 then
 return redis.call('del', key)
 end
 LUA;
 
 $this->redis->eval($script, [$this->scene, $this->lockValue], 1);
 }
 }
 
 | 
实例:
 demo.php
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | <?php
 include 'Lock.php';
 
 use Swoole\Timer;
 
 
 
 
 
 $Lock = new Lock();
 
 Timer::tick(1000, function($timer_id) use ($Lock){
 if ($Lock->lock()) {
 echo '['.date('Y-m-d H:i:s').'] ' . '请求成功!' . PHP_EOL;
 
 
 $Lock->unLock();
 } else {
 echo '['.date('Y-m-d H:i:s').'] ' . '操作频繁,请稍候再试!' . PHP_EOL;
 }
 });
 
 | 
搞定!
      
     
    
      
  
  
    
      
      
        
        搭建个人博客主要为了记录以及提升技术,希望跟大家一起学习!