工装设计方案网站python基础教程电子书

当前位置: 首页 > news >正文

工装设计方案网站,python基础教程电子书,采用什么方法推广网站,建设视频网站费用吗提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 Redis分布式锁最简单的实现如何避免死锁#xff1f;锁被别人释放怎么办#xff1f;锁过期时间不好评估怎么办#xff1f;–看门狗分布式锁加入看门狗 redissonRe… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 Redis分布式锁最简单的实现如何避免死锁锁被别人释放怎么办锁过期时间不好评估怎么办–看门狗分布式锁加入看门狗 redissonRedLock 红锁Redlock实现整体流程RedLock的是是非非RedLock总结 对比zk实现分布式锁 Redis分布式锁最简单的实现 想要实现分布式锁必须要求 Redis 有「互斥」的能力我们可以使用 SETNX 命令这个命令表示SET if Not Exists即如果 key 不存在才会设置它的值否则什么也不做。 两个客户端进程可以执行这个命令达到互斥就可以实现一个分布式锁。 客户端 1 申请加锁加锁成功 客户端 2 申请加锁因为它后到达加锁失败 此时加锁成功的客户端就可以去操作「共享资源」例如修改 MySQL 的某一行数据或者调用一个 API 请求。 操作完成后还要及时释放锁给后来者让出操作共享资源的机会。如何释放锁呢 也很简单直接使用 DEL 命令删除这个 key 即可这个逻辑非常简单。 但是它存在一个很大的问题当客户端 1 拿到锁后如果发生下面的场景就会造成「死锁」 1、程序处理业务逻辑异常没及时释放锁 2、进程挂了没机会释放锁 这时这个客户端就会一直占用这个锁而其它客户端就「永远」拿不到这把锁了。怎么解决这个问题呢 如何避免死锁 我们很容易想到的方案是在申请锁时给这把锁设置一个「租期」。 在 Redis 中实现时就是给这个 key 设置一个「过期时间」。这里我们假设操作共享资源的时间不会超过 10s那么在加锁时给这个 key 设置 10s 过期即可 SETNX lock 1 // 加锁 EXPIRE lock 10 // 10s后自动过期这样一来无论客户端是否异常这个锁都可以在 10s 后被「自动释放」其它客户端依旧可以拿到锁。 但现在还是有问题 现在的操作加锁、设置过期是 2 条命令有没有可能只执行了第一条第二条却「来不及」执行的情况发生呢例如 SETNX 执行成功执行EXPIRE 时由于网络问题执行失败SETNX 执行成功Redis 异常宕机EXPIRE 没有机会执行SETNX 执行成功客户端异常崩溃EXPIRE也没有机会执行 总之这两条命令不能保证是原子操作一起成功就有潜在的风险导致过期时间设置失败依旧发生「死锁」问题。 在 Redis 2.6.12 之后Redis 扩展了 SET 命令的参数用这一条命令就可以了 SET lock 1 EX 10 NX锁被别人释放怎么办 上面的命令执行时每个客户端在释放锁时都是「无脑」操作并没有检查这把锁是否还「归自己持有」所以就会发生释放别人锁的风险这样的解锁流程很不「严谨」如何解决这个问题呢 解决办法是客户端在加锁时设置一个只有自己知道的「唯一标识」进去。 例如可以是自己的线程 ID也可以是一个 UUID随机且唯一这里我们以UUID 举例 SET lock \(uuid EX 20 NX之后在释放锁时要先判断这把锁是否还归自己持有伪代码可以这么写 if redis.get(lock) \)uuid:redis.del(lock)这里释放锁使用的是 GET DEL 两条命令这时又会遇到我们前面讲的原子性问题了。这里可以使用lua脚本来解决。 安全释放锁的 Lua 脚本如下 if redis.call(GET,KEYS[1]) ARGV[1] thenreturn redis.call(DEL,KEYS[1]) elsereturn 0 end好了这样一路优化整个的加锁、解锁的流程就更「严谨」了。 这里我们先小结一下基于 Redis 实现的分布式锁一个严谨的的流程如下 1、加锁 SET lock_key \(unique_id EX \)expire_time NX2、操作共享资源 3、释放锁Lua 脚本先 GET 判断锁是否归属自己再DEL 释放锁 锁过期时间不好评估怎么办–看门狗 看上面这张图加入key的失效时间是10s但是客户端C在拿到分布式锁之后然后业务逻辑执行超过10s那么问题来了在客户端C释放锁之前其实这把锁已经失效了那么客户端A和客户端B都可以去拿锁这样就已经失去了分布式锁的功能了 比较简单的妥协方案是尽量「冗余」过期时间降低锁提前过期的概率但是这个并不能完美解决问题那怎么办呢 分布式锁加入看门狗 加锁时先设置一个过期时间然后我们开启一个「守护线程」定时去检测这个锁的失效时间如果锁快要过期了操作共享资源还未完成那么就自动对锁进行「续期」重新设置过期时间。 这个守护线程我们一般也把它叫做「看门狗」线程。 为什么要使用守护线程 redisson github项目 redisson 实现分布式锁和同步器可以直接调用 https://github.com/redisson/redisson/ 基于Redis的Redisson分布式可重入锁RLock Java对象实现了java.util.concurrent.locks.Lock接口。同时还提供了异步Async、反射式Reactive和RxJava2标准的接口。 RLock lock redisson.getLock(anyLock); // 最常见的使用方法 lock.lock();大家都知道如果负责储存这个分布式锁的Redisson节点宕机以后而且这个锁正好处于锁住的状态时这个锁会出现锁死的状态。为了避免这种情况的发生Redisson内部提供了一个监控锁的看门狗它的作用是在Redisson实例被关闭前不断的延长锁的有效期。默认情况下看门狗的检查锁的超时时间是30秒钟也可以通过修改Config.lockWatchdogTimeout来另行指定。 另外Redisson还通过加锁的方法提供了leaseTime的参数来指定加锁的时间。超过这个时间后锁便自动解开了。 // 加锁以后10秒钟自动解锁 // 无需调用unlock方法手动解锁 lock.lock(10, TimeUnit.SECONDS);// 尝试加锁最多等待100秒上锁以后10秒自动解锁 boolean res lock.tryLock(100, 10, TimeUnit.SECONDS); if (res) {try {…} finally {lock.unlock();} }Redisson同时还为分布式锁提供了异步执行的相关方法 RLock lock redisson.getLock(anyLock); lock.lockAsync(); lock.lockAsync(10, TimeUnit.SECONDS); FutureBoolean res lock.tryLockAsync(100, 10, TimeUnit.SECONDS);RLock对象完全符合Java的Lock规范。也就是说只有拥有锁的进程才能解锁其他进程解锁则会抛出IllegalMonitorStateException错误。但是如果遇到需要其他进程也能解锁的情况请使用分布式信号量Semaphore 对象. RedLock 红锁 Redis 作者提出的 Redlock方案是如何解决主从切换后锁失效问题的。 Redlock 的方案基于一个前提 不再需要部署从库和哨兵实例只部署主库但主库要部署多个官方推荐至少 5 个实例。 注意不是部署 Redis Cluster就是部署 5 个简单的 Redis 实例。它们之间没有任何关系都是一个个孤立的实例。 做完之后我们看官网代码怎么去用的 RLock lock1 redissonInstance1.getLock(lock1); RLock lock2 redissonInstance2.getLock(lock2); RLock lock3 redissonInstance3.getLock(lock3);RedissonRedLock lock new RedissonRedLock(lock1, lock2, lock3); // 同时加锁lock1 lock2 lock3 // 红锁在大部分节点上加锁成功就算成功。 lock.lock(); … lock.unlock();红锁RedLock 基于Redis的Redisson红锁 RedissonRedLock对象实现了Redlock介绍的加锁算法。该对象也可以用来将多个 RLock对象关联为一个红锁每个 RLock对象实例可以来自于不同的Redisson实例。 Redlock实现整体流程 1、客户端先获取「当前时间戳T1」 2、客户端依次向这 5 个 Redis 实例发起加锁请求 3、如果客户端从 3 个大多数以上Redis 实例加锁成功则再次获取「当前时间戳T2」如果 T2 - T1 锁的过期时间此时认为客户端加锁成功否则认为加锁失败。 4、加锁成功去操作共享资源 5、加锁失败/释放锁向「全部节点」发起释放锁请求。 所以总的来说客户端在多个 Redis 实例上申请加锁必须保证大多数节点加锁成功大多数节点加锁的总耗时要小于锁设置的过期时间释放锁要向全部节点发起释放锁请求。 RedLock的是是非非 RedLock总结 对比zk实现分布式锁 Zookeeper–08—zk实现分布式锁、案例