南宁建设厅官方网站,电商网页设计教程,建设集团领导班子名单,教育教学成果展示网站建设目录一、为什么需要分布式锁二、分布式锁的实现方案三、redis分布式锁3.1 简单实现3.2 成熟的实现一、为什么需要分布式锁 1.在java单机服务中#xff0c;jvm内部有一个全局的锁监视器#xff0c;只有一个线程能获取到锁#xff0c;可以实现线程之间的互斥 2.当有多个java服…
目录一、为什么需要分布式锁二、分布式锁的实现方案三、redis分布式锁3.1 简单实现3.2 成熟的实现一、为什么需要分布式锁 1.在java单机服务中jvm内部有一个全局的锁监视器只有一个线程能获取到锁可以实现线程之间的互斥 2.当有多个java服务时会有多个jvm也会有多个锁监视器这样没办法使得多个jvm之间的线程互斥所以无法使用jvm内部的锁监视器也就是synchronized关键字无法用于此场景 3.需要在多个jvm外部加一个锁监视器这样保证不同的jvm的线程保持互斥 4.满足分布式系统或者集群模式下多个进程都可见并且互斥的锁 5.分布式锁满足的特性多进程可见、互斥、高可用、高性能、安全 6.分布式锁是否可重入 7.分布式锁是否公平
二、分布式锁的实现方案 1.mysql实现利用mysql内部的写操作本身的互斥锁可以开启一个事务执行业务业务执行完之后提交事务释放锁当业务出现异常事务回滚释放锁。可用性好性能一般断开连接也会释放锁是安全的 2.redis实现利用setnx的互斥命令当key存在的时候set值会失败当key不存在的时候才会set成功删除key之后锁便能释放。redis集群可用性得到保障高性能。给key加上过期时间即使服务器宕机redis重启key到期失效锁也会自动失效解决安全性问题。key的过期时间也是有讲究的如果过短业务还未处理完便释放了锁会有问题。如果过长无效的等待时间会变多。 3.zookeeper实现利用节点的唯一性和有序性实现互斥。zookeeper可以集群可用性好zookeeper是强一致性性能上比redis差节点是临时节点服务器宕机节点断开连接会自动释放
三、redis分布式锁
3.1 简单实现 1.获取锁setnx lock threadlock不存在则设置keylock存在则设置不了lock 2.释放锁del key如果服务宕机没有del key会导致key一直存在造成死锁 3.设置过期时间expire lock 10lock在10秒后自动过期 4.若setnx lock thread之后还没来得及expire lock 10服务器宕机仍然会死锁是用一个set命令保证原子性即set lock thread ex 10 nx5.获取锁失败会有两种机制一是继续等待等到有线程释放锁为止阻塞式获取二是非阻塞是获取如果获取失败会尝试再获取一次如果还是失败则立即结束返回结果。阻塞式实现比较麻烦对cpu也会产生压力6.非阻塞式分布式锁实现过程尝试获取锁获取锁成功执行业务业务如果超时或者宕机则释放锁业务执行完毕也会释放锁 7.误删锁情况线程1获取到锁由于业务处理时间过长锁超时释放此时线程2获取到锁执行业务业务时间也长线程1此时业务处理完毕然后释放了锁线程3此时拿到锁执行业务那么此时线程2和线程3的执行业务就是非互斥的造成并发不安全。 8.对于无删除锁情况锁的value中应该存一份线程的标识可以用uuid若是线程的id集群情况下会发生线程id重复的情况实现过程线程1获取到锁并存入线程标识获取锁成功开始执行业务若业务超时或服务宕机自动释放锁若业务执行完毕且没有超时判断锁标识是否是线程1的如果是则释放锁 9.非原子操作情况线程1获取到锁然后处理业务业务处理完毕准备释放锁判断锁标识是否是线程1的判断是的开始释放锁此时线程1阻塞jvm发生FullGC,导致redis锁超时释放GC完毕线程2获取到锁开始执行业务业务时间较长线程1阻塞结束释放掉了锁线程3获取到锁执行业务此时线程2和线程3的业务处理产生并发问题。所以需要线程1判断锁标识的操作和释放锁的操作要保证原子性需要用lua脚本实现 10.还有其它问题例如不可重入同一个线程无法多次获取同一个锁不可重试获取锁只尝试一次就返回false没有重试机制超时释放超时释放可以避免死锁但业务处理时间过长导致锁超时释放会存在安全隐患主从一致性问题如果redis提供了主从集群线程1在主机上设置了锁主从同步存在延迟当主机宕机时从机没有同步到主机上的锁数据线程2读从机时未发现到锁线程2也能拿到锁此时从机被推选为主机并缓存了线程2的锁此时线程1和线程2在业务处理上存在并发问题
3.2 成熟的实现 1.开源框架redission