redisson分布式锁

if ((redis.call('exists', KEYS[1]) == 0) or (redis.call('hexists', KEYS[1], ARGV[2]) == 1)) //如果这个锁不存在(还没被任何人持有)或者,这个锁已经被我(当前线程)持有了(重入)
then
redis.call('hincrby', KEYS[1], ARGV[2], 1); //把当前线程在锁中的“计数器”加 1。
redis.call('pexpire', KEYS[1], ARGV[1]); //设置过期时间
return nil;
end;

return redis.call('pttl', KEYS[1]); //无法加锁,则返回锁的剩余生存时间

参数:
KEYS[1] 锁的 Redis 键名(如 "my-lock")
ARGV[1] 锁的过期时间(单位:毫秒)
ARGV[2] 客户端标识(唯一标识某个线程),如 "uuid:thread-id"

锁在redis里用hash表来保存:
普通锁:
dc2403e7-1aa4-4120-908c-3d558a99c384:1 1 //value 表示该线程加锁的次数

读锁:
mode:read //表示当前是读模式
fe0cc1f4-2d16-49f1-a101-c758b02b4b5a:1 1 //获取锁的线程1
dc2403e7-1aa4-4120-908c-3d558a99c384:81 1 //获取锁的线程2

如何解决redis主备切换锁丢失的问题?
方案1:使用RedLock 但是需要三套独立的redis,注意主备只算一套,成本太高

RLock lock1 = redissonClient1.getLock("myLock");
RLock lock2 = redissonClient2.getLock("myLock");
RLock lock3 = redissonClient3.getLock("myLock");

RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3);
redLock.lock();
// ... critical section ...
redLock.unlock();

方案2: 获取锁时使用wait命令等待同步到备节点再返回
wait命令用法:WAIT <numreplicas> <timeout>
需要考虑如果wait超时应该怎么办,不处理,还是回滚,重试?

String result = jedis.set("lock:abc", "1", SetParams.setParams().nx().px(10000));
if ("OK".equals(result)) {
    Long ack = jedis.waitReplicas(1, 1000);
    if (ack < 1) {
        // WAIT 超时,锁未被安全复制,主动释放锁
        jedis.del("lock:abc");
        System.out.println("锁复制失败,主动释放锁并放弃操作");
    } else {
        System.out.println("锁已同步到副本,可以继续执行临界区");
        // 执行业务逻辑
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容