Redis+Lua锁 发表于 2017-12-19 | 分类于 PHP 一、Redis单例12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758/** * Redis单例 * * User: xiangqian * Date: 17/8/3 * Time: 下午3:40 */namespace Model\Redis;use \Redis;class BaseModel{ private static $_instances = []; public $redis; /** * 构造方法 * * BaseModel constructor. * @param array $config */ private function __construct(array $config) { try { $this->redis = new Redis(); $this->redis->connect($config['host'], $config['port'], $config['time_out']); $this->redis->auth($config['auth']); } catch (\RedisException $e) { exit($e->getMessage()); } } /** * 获取实例 * * @param array $config * @return BaseModel */ public static function getInstance(array $config) { ksort($config); $key = md5(serialize($config)); if (isset(self::$_instances[$key]) && self::$_instances[$key] instanceof self) { return self::$_instances[$key]; } self::$_instances[$key] = new self($config); return self::$_instances[$key]; } /** * 禁止克隆 */ public function __clone() { trigger_error('can not clone', E_USER_ERROR); }} 二、Redis + Lua锁实现12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758/** * Redis + Lua实现锁 * * User: xiangqian * Date: 17/12/19 * Time: 下午5:14 */namespace Model\Redis;class Lock{ private static $redisConfig = [ 'host' => '127.0.0.1', 'port' => 6379, 'time_out' => 1, 'auth' => '123456' ]; /** * 加锁 * * @param $key * @param $token * @param int $ttl * @return int */ public static function lock($key, $token, $ttl = 100) { $script = ' local ok = redis.call("setnx", KEYS[1], ARGV[1]) if ok == 1 then redis.call("expire", KEYS[1], ARGV[2]) end return ok'; return BaseModel::getInstance(self::$redisConfig)->redis->eval($script, [$key, $token, $ttl], 1); } /** * 释放锁 * * @param $key * @param $token * @return int */ public static function unlock($key, $token) { $script = ' if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end'; return BaseModel::getInstance(self::$redisConfig)->redis->eval($script, [$key, $token], 1); }} 三、使用示例12345$key = 'test_key'; //根据业务定名称$token = uniqid($key); //每个请求生成唯一的token, 防止被别的请求释放锁Lock::lock($key, $token, 60); //加锁#do something with lockLock::unlock($key, $token); //释放锁