Redis-分布式锁

1. 概念

分布式锁是为了解决不同进程需要互斥地访问共享资源产生的。在分布式模式下,假如某份数据只有一份或者存在限制,那么我们就需要使用锁技术来控制某一时刻修改数据的进程数。

2. 实现方式

  1. 基于数据库实现分布式锁;如mysql排它锁。
  2. 基于缓存(Redis等)实现分布式锁; 本文介绍内容。
  3. 基于Zookeeper实现分布式锁。

3. 几个属性

  1. 安全属性:互斥,不管任何时候,只有一个客户端能持有同一个锁。
  2. 效率属性A:不会死锁,最终一定会得到锁,就算一个持有锁的客户端宕掉或者发生网络分区。
  3. 效率属性B:容错,只要大多数Redis节点正常工作,客户端应该都能获取和释放锁。
  4. 解铃还须系铃人:加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

4. 思路及实现

  • redis分布式锁的实现主要基于redis的SETNX命令,若给定的 key 已经存在,SETNX 不做任何动作。否则将 key 的值设为 value,成功返回1,失败返回0。
  • 使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功。
  • 为了防止获取锁后程序出现异常,导致其他线程/进程调用SETNX命令总是返回0而进入死锁状态,需要为该key设置一个“合理”的过期时间。
  • 释放锁,使用DEL命令将锁数据删除。
<?php
class RedisLockService
{
	const LOCK_SUCCESS = 'OK';
	const IF_NOT_EXISTS = 'NX';
	const MILLISECOND_EXPIRE_TIME = 'EX';
	const EXPIRE_TIME = 50;
	
	/**
	* @param $key
	* @param $uuid
	* @param $expire_time 
	* 加锁
	*/
	public function lock($key,$uuid,$expire_time = '')
	{
		if (empty($expire_time)) {
			$expire_time = self::EXPIRE_TIME;
		}
		$res = Redis::set($key,$uuid,self::MILLISECOND_EXPIRE_TIME ,$expire_time,self::IF_NOT_EXISTS);
		if ($res == self::LOCK_SUCCESS) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	* @param $key
	* @param $uuid
	* 释放锁
	*/
	public function unlock($key,$uuid)
	{
		$lua =<<<LUA_SCRIPT
if redis.call("get",KEYS[1]) == ARGV[1] then
	return redis.call("del",KEYS[1])
else
	return 0
end
LUA_SCRIPT;
		return Redis::eval($lua,1,$key,$uuid);
	}
}
?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值