php使用redis分布式锁,redis分布式锁如何实现

fccb603a33588e756ff8c253b31b7905.png

redis分布式锁:

1、实现原理

利用redis中的set命令来实现分布式锁。

从Redis 2.6.12版本开始,set可以使用下列参数:

SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]

EX second :设置键的过期时间为second秒。 SET key value EX second效果等同于SETEX key second value 。

PX millisecond :设置键的过期时间为millisecond毫秒。 SET key value PX millisecond效果等同于PSETEX key millisecond value 。

NX :只在键不存在时,才对键进行设置操作。 SET key value NX效果等同于SETNX key value 。

XX :只在键已经存在时,才对键进行设置操作。

返回值:

SET 在设置操作成功完成时,才返回OK 。

如果设置了NX或者XX ,但因为条件没达到而造成设置操作未执行,那么命令返回空批量回复(NULL Bulk Reply)。

命令:

> SET key value EX ttl NX

大致思想是:

(a)SET lock currentTime+expireTime EX 600 NX,使用set设置lock值,并设置过期时间为600秒,如果成功,则获取锁;

(b)获取锁后,如果该节点掉线,则到过期时间ock值自动失效;

(c)释放锁时,使用del删除lock键值;

使用redis单机来做分布式锁服务,可能会出现单点问题,导致服务可用性差,因此在服务稳定性要求高的场合,官方建议使用redis集群(例如5台,成功请求锁超过3台就认为获取锁),来实现redis分布式锁。详见RedLock。

2、优点

性能高,redis可持久化,也能保证数据不易丢失;

redis集群方式提高稳定性。

3、缺点

使用redis主从切换时可能丢失部分数据。

4、开源实现

python版本的开源实现:python-redis-lock。

redis分布式锁的具体实现方式:

加锁和解锁的方式:private static final String LOCK_SUCCESS = "OK";

private static final String SET_IF_NOT_EXIST = "NX";

private static final String SET_WITH_EXPIRE_TIME = "PX";

private static final Long RELEASE_SUCCESS = 1L;

/**

* 尝试获取分布式锁

* @param lockKey 锁

* @param requestId 请求标识

* @param expireTime 超期时间

* @return 是否获取成功

*/

public Boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {

Jedis jedis = this.jedisPool.getResource();

String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

if (LOCK_SUCCESS.equals(result)) {

return true;

}

return false;

}

/**

* 释放分布式锁

* @param lockKey 锁

* @param requestId 请求标识

* @return 是否释放成功

*/

public Boolean releaseDistributedLock(String lockKey, String requestId) {

Jedis jedis = this.jedisPool.getResource();

String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

if (RELEASE_SUCCESS.equals(result)) {

return true;

}

return false;

}

2、具体的应用try{

String requestId = UUID.randomUUID().toString();

Boolean flag = tryGetDistributedLock(lock,requestId,1000);

int n = 0;

while(!flag){

//如果没有获取锁,可以尝试下一个lock,如果都没有,则尝试 n 次,退出

...

if(n++>5){ throw new Exception("尝试获取锁失败");}

...

}

if(!flag){

throw new Exception("尝试获取锁失败");

}

}catch(){

}finally{

releaseDistributedLock(lock,requestId);

}

更多Redis相关知识,请访问Redis使用教程栏目!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值