基于Redis的分布式锁

基于Redis的分布式锁

背景

主要最近在研究红包,抽奖,秒杀各类活动,考虑到多台服务器上,可能会获取到旧数据,所以上网查询了下方法,了解了分布式锁,一般是数据库的乐观锁或者用zookeeper或者reids做分布式锁,基本原理:用一个状态值表示锁,对锁的占用和释放通过状态值来标识。在这里做了下笔记。

基本的命令

1、SETNX(SET if Not eXists)
SETNX key value
将 key 的值设为 value ,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。
返回值:
设置成功,返回 1 。
设置失败,返回 0 。
2、GET
GET key
返回 key 所关联的字符串值。
返回值:
当 key 不存在时,返回 nil ,否则,返回 key 的值。
如果 key 不是字符串类型,那么返回一个错误。
3、GETSET
GETSET key value
将给定 key 的值设为 value ,并返回 key 的旧值(old value)。
返回值:
返回给定 key 的旧值。
当 key 没有旧值时,也即是, key 不存在时,返回 nil 。
4、DEL
DEL key [key …]
删除给定的一个或多个 key 。
返回值:
被删除 key 的数量。

实现(伪代码)

        if (SETNX(key, timestamp)) {
            //获得锁,可以进行下步操作
            return true;
        } else {
            //获取锁失败,需要先判断是否锁超时了,因为可能存在之前步骤获取锁后,超时宕机等情况,所以需要判断
            currentTimestamp = get(key);
            //如果其他线程设置了时间,这个判断不成立
            if (currentTimestamp<System.currentTimeMillis(){
                oldTimestamp = GETSET(key, nowTimestamp);
                //获取上一个锁到期时间,并设置现在的锁到期时间,
                //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的
                if (oldTimestamp.equal(currentTimestamp)) {
                    //获得锁,可以进行下步操作
                    return true;
                }
            }
            //可以继续循环,等待获取锁
            return false;
        }

问题

为什么前面的锁已经超时了,还要用getSet去设置新的时间戳的时间获取旧的值,然后和外面的判断超时时间的时间戳比较呢?
基于Redis的分布式锁

因为是分布式的环境下,可以在前一个锁失效的时候,有两个进程进入到锁超时的判断。如:
C0超时了,还持有锁,C1/C2同时请求进入了方法里面
C1/C2获取到了C0的超时时间
C1使用getSet方法
C2也执行了getSet方法
假如我们不加 oldValueStr.equals(currentValueStr) 的判断,将会C1/C2都将获得锁,加了之后,能保证C1和C2只能一个能获得锁,一个只能继续等待。

Reference:
1. http://blog.csdn.net/ugg/article/details/41894947/
2. http://www.cnblogs.com/0201zcr/p/5942748.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值