PHP Redis实现同步锁

接上文同步锁(用文件实现)
用文件的形式实现同步锁,需要对应目录有读写权限,有IO性能消耗,而且会生成残留文件, 其实也可以借助redis达到同样的效果
Redis是线程安全的,可以把Redis看成单线程的模型.

首先来看Redisset命令

原生命令如下
set key value [EX seconds] [PX milliseconds] [NX|XX]
参数说明
*key 
*value
*[EX seconds] 可选,过期时间 单位秒
*[PX milliseconds] 可选,过期时间 单位毫秒
*[NX|XX] 可选,NX表示key不存在时执行set命令
              XX表示key存在时执行set命令

来个例子实验一下

设置name->zhangsan
过期时间20秒,且内存中不存在名为name的key时,命令执行
127.0.0.1:6379> set name zhangsan EX 20 NX 

执行两遍相同命令,只有第一条返回OK

image.png

PHP实现

用composer 下载Redis三方包,不同的包操作可能会有些差异.
我用的是Predis

<?php
namespace lock;
require_once 'lib/vendor/autoload.php';
use \Predis\Client;
class RedisLock
{
    private $client;
    private $key;
    /**
     * RedisLock constructor.
     *
     * @param $key
     */
    public function __construct ($key) {
        \Predis\Autoloader::register();
        $client = new Client([
            'scheme' => 'tcp',
            'host'   => '127.0.0.1',
            'port'   => 6379,
        ]);
        $this->client = $client;
        $this->key    = $key;
    }
    /**
     * 获取锁
     * 
     * @return mixed
     */
    function getLock(){
        return $this->client->set($this->key,1,'EX',10,'NX');
    }
    /**
     * 清除锁
     */
    function clearLock(){
        $this->client->del($this->key);
    }
}

测试

<?php
use lock\RedisLock;
require_once 'RedisLock.php';

if (!isset($argv[1])){
    echo '输入cacheKey';
    return;
}
//获取输入的cacheKey
$cacheKey = $argv[1];

$redisLock = new RedisLock($cacheKey);
if($redisLock->getLock())
{
    echo "读库-$cacheKey".PHP_EOL;
    sleep(60);
    //TODO 设置缓存
    $redisLock->clearLock();
}else{
    echo "获取锁失败$cacheKey";
}

效果
image.png

image.png

确保只有一个线程进入读取数据库的代码段.就能避免缓存击穿问题.

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容