如何使用Redis创建分布式锁?

 伊那里 发布于 2023-02-08 15:48

在redis文档中,我发现可以通过SETNX实现原始锁:

http://redis.io/commands/setnx

C4发送SETNX lock.foo以获取锁

崩溃的客户端C3仍然保留它,因此Redis将回复0到C4.

C4发送GET lock.foo来检查锁是否过期.如果不是,它会睡一段时间并从头开始重试.

相反,如果锁定已到期,因为lock.foo上的Unix时间早于当前的Unix时间,C4会尝试执行:

GETSET lock.foo

由于GETSET语义,C4可以检查存储在key中的旧值是否仍然是过期时间戳.如果是,则获得锁定.

如果另一个客户端(例如C5)比C4快并且通过GETSET操作获得锁定,则C4 GETSET操作将返回未过期的时间戳.C4将从第一步开始重新启动.请注意,即使C4将来设置密钥几秒钟,这也不是问题.

但是,正如一些用户所评论的那样,使用UNIX时间戳作为过期时间需要客户端和服务器的时间完全同步.有没有更好的替代方法在Redis中创建全局/分布式锁?

2 个回答
  • 使用redis> = 2.6,LUA脚本解决方案会很棒.Lua脚本总是原子地执行所以:

    --lockscript, parameters: lock_key, lock_timeout
    local lock = redis.call('get', KEYS[1])
    if not lock then    
        return redis.call('setex', KEYS[1], ARGV[1], "locked");
    end
    return false
    

    另一种基于新SET命令选项的解决方案

    SET lock_key "locked" EX lock_timeout NX 
    

    使用redis <2.6可以使用带有multi的模式:

    MULTI
    SETNX tmp_unique_lock some_value
    EXPIRE tmp_unique_lock
    RENAMENX tmp_unique_lock real_lock
    EXEC
    

    2023-02-08 15:51 回答
  • SET而不是SETNX.SET接受过期时间的参数,以秒和毫秒为单位,而不是UNIX时间戳值.

    仅基于历史原因记录旧的基于SETNX的模式.

    来自SETNX 描述:

    注意:从Redis 2.6.12开始,可以使用SET命令创建更简单的锁定原语来获取锁,并使用简单的Lua脚本来释放锁.该模式记录在SET命令页面中.

    2023-02-08 15:54 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有