分布式锁
参考
- www.php.cn/redis/48784…
- blog.csdn.net/chihaihai/a…
- www.php.cn/redis/48784…
- www.cnblogs.com/youngdeng/p…
- www.zhihu.com/question/30…
- **blog.csdn.net/asd05137730…
cloud.tencent.com/developer/a…
- B站图灵
- B站马士兵
分布式锁本质是高并发请求导致的数据不一致
- Redis方案
- Zookper方案
- MySQL方案
场景
情况一:加Synchronized。可以解决单体应用,但是解决不了应用的分布式场景。(Synchronized是在JVM里面)
情况二:Redis单机。redis 的setNX命令加锁。但是从“高可用”的层面来看,仍然是有所欠缺,也就是说当 redis 是单点的情况下,当发生故障时,则整个业务的分布式锁都将无法使用。需要通集群来解决。另外,比如不可重入、非阻塞、误解别的线程的锁、未执行完锁就失效、主从切换锁丢失。
情况三:Redis集群。redission分布式锁方案。
步骤
RedissonClient是线程安全的,内部通过Netty通信,所以除了同步执行方式,也支持异步执行。同步我们使用RedissonClient,异步使用RedissonReactiveClient.redisson则支持锁的可重入和等待获取锁,并在解锁时判断是否是当前线程持有的锁,以及有看门狗机制防止锁过期程序还未执行完的问题。但是解决不了主从架构同步时所丢失的问题。这个需要Redlock机制。
情况四:布隆筛选器。
情况五:Redlock机制。
情况六:其他问题。
比如Redis如何提高锁的效率。
存在的问题
- 锁具备原子性。
- 加锁一个命令
- 或者解锁LUA脚本【if是本线程所持有,那么删除】。已经通过redission实现。
- LUA脚本:Lua脚本在Redis中是以原子方式执行的,在Redis服务器执行EVAL命令时,在命令执行完毕并向调用者返回结果之前,只会执行当前命令指定的Lua脚本包含的所有逻辑,其它客户端发送的命令将被阻塞,直到EVAL命令执行完毕为止。因此LUA脚本不宜编写一些过于复杂了逻辑,必须尽量保证Lua脚本的效率,否则会影响其它客户端。
-
锁的唯一性(A删除B的锁):客户端在加锁时,设置一个只有自己知道的「唯一标识」进去,防止自己的锁被别人释放了。
-
死锁问题,忘记释放锁,命令设置失效时间。
- 锁超时问题。加锁时,先设置一个过期时间,然后开启守护线程,定期检测失效时间;如果锁快要过期了,共享资源还未完成,自行续期。
- 数据库事务超时。使用redisson客户端设置分布式锁的时候,如果担心有业务逻辑没有执行完毕而锁过期的情况,会使用看门狗监控锁进行兜底,防止服务的宕机。看门狗的时间可以在配置中使用LockWatchdogTimeout 进行设置,视业务情况而定。
-
锁的可重入问题。value中多存储一个 全局唯一的requestId,代表客户端请求标识。具体可以使用UUID。在重入的情况下使用同一个UUID,就能判断是否是一个请求的锁重入,从而获取锁。另外记录加锁的次数,每次加锁+1。
-
大量请求失败,设置自旋锁等待。