记录一次redis分布式锁的坑

94 阅读1分钟

redis分布式锁的实现方式是:

lock(){
    sync(this){
        //无法获取自旋

        setnx(key,UUID)

        setex(60s)

        return UUID

    }
}    

unlock(key,value){

    sync(this){
        if(get(key) == UUID){
            del(key)
        }
    }
}    

备注:由于redisTemplate版本问题,没有setnxex的原子操作,而且unlock也有两步操作,为了保证单机原子性,加上了sync对象锁,并且lock和unlock锁同一个对象。

看山去一切都很美,但是运行起来发现问题了:并发量一上来,分布式锁并不会正常解锁,而是每次都要等60s自动过期后才能解锁。。。。

仔细分析了下问题原因:

线程A先进入lock方法,获取sync对象锁,获取到分布式锁,释放sync对象锁

线程A执行业务代码

线程B进入lock方法,获取sync对象锁,但无法获取分布式锁,自旋等待

线程A进入unlock方法,尝试获取sync对象锁,但此时sync对象锁被线程B占用,需要等待线程B释放sync对象锁

这时线程A B有死锁,需要等待其中一个锁自动解锁,就是分布式锁的60s,这就解释了为什么每次都要等60s!!!!

而且这种方法还只能在单机保证线程安全,想要实现一个优秀的分布式锁,还必须要满足分布式原子性!