分布式锁的实现方式

1. 使用mysql中的排他锁

开启不自动提交事务

select xx for update //上锁

手动提交事务 //释放锁

一般不使用这种方式,因为如果数据库异常,数据库释放锁的时间会相对较长,且数据库压力会比较大。

当然也可以用其他排他锁,如update语句、insert语句等。

2. 使用redis

方法1. 

setnx kkk vvv //加锁

expire kkk 10 //设置锁的超时时间,秒

del kkk //释放锁

上面是利用setnx命令只能设置一次,重复设置会失败的特点。

上面的写法有两个问题:

1. 如果第2行没来得及执行,可能就永远释放不了锁了;

2. 第3行的写法可能被别的客户端执行,这就是说别人可能释放自己的锁。

方法2. 加原子性

这是推荐的写法,解决上面方法的两个问题。

set kkk vvv ex 10 nx

用lua脚本里释放锁

第1行里,用一行代码执行加锁和设置超时时间,确保了这两个操作的原子性。

“用lua”脚本释放锁的时候,要先get判断锁是否是自己的,再del删除。为什么要用lua脚本?因为它有原子性。

方法3. 加看门狗

方法2还存在超时时间如何设置的问题:设置太短,有可能事情还没干完锁就自动释放了;设置越长锁持有时间就会越久,事情干完了还拿着半天锁。

解决办法就是加看门狗,增加一个后台线程,在锁快到期的时候去看看加锁的线程是不是还活着,如果活着,就帮它延一下时间。

项目中一般不自己写上面的redis相关的代码,而是直接用Redisson这个工具,它解决了上面的问题,也有看门狗。

3. 使用zookeeper(不推荐了)

使用zk的临时顺序节点来做分布式锁。

临时的意思是抢到锁的客户端如果没有正常释放锁(比如崩溃了、逻辑错误),zk自己会超时释放锁。

上锁流程为:

1.去zk创建节点,如果创建成功,判断节点是不是序号最小的,如果是,则抢锁成功,否则抢锁失败。

2.如果抢锁失败,就去监听比自己小的节点,如果比自己小的节点不在了,就算重新抢到锁了。

使用监听机制而非轮询机制,是因为轮询的效率太低,且系统开销较大。

事情做完后删除节点,代表释放锁。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值