- 基于数据库的分布式锁
A:基于表记录(唯一索引确保业务锁唯一)
创建一张表,基于表中的数据实现是否获取/释放锁。
获取锁则往表中插入特定的数据,释放则删除
优点:简单
缺点:
1.锁不存在过期时间,释放锁失败则需要人为维护
2.依赖数据库,需要保证数据库高可用。
3.锁非阻塞,无法保证一次性获取锁成功,需要人为维护逻辑(循环插入)
4.锁非可重入(变更为可重入需要加特殊信息处理)
B:基于乐观锁(基于A)
需要加锁的业务数据加上版本等信息维护锁(cas)确定是否是获取锁的版本确 定数据是否被更改。
优点:简单,对于单一请求可保证数据正确,适合读多写少
缺点:
1.不适用并发情况
2.数据库冗余更多信息
3.version的频繁变更会导致大量请求失败。
C:基于悲观锁
在查询语句后面增加FOR UPDATE,使查询时数据库加上排它锁。
根据查询数据库表时是否明确查询索引字段的条件决定是加行锁/表锁
优点:可以解决并发下的分布式锁
缺点:
1.需要关闭自动提交,手动提交
2.每次请求都会额外产生加锁的开销且未获取到锁的请求将会阻塞等待锁
3.可能产生死锁
4.mysql自动优化查询可能不走索引,导致加表锁。 - 基于redis
原理:在redis设置了某key相当于加了锁,删除即释放锁
需要考虑的问题:
1.需要给锁加过期时间防止删除失败(过期时间逻辑复杂)
2.redis部署
1.单机模式:容易产生单点问题(服务挂了就无法增加/释放锁)
2.Master-Slave+Sentinel 选举模式 :主模式挂了重新选举容易产生锁丢失
3.Redis Cluster 模式:算法无法保证加锁一定正确
适用的工具:Redisson
1.所有指令都通过 Lua 脚本执行
2.默认key的过期事件为30s,看门狗保证key不会提前释放(获取锁后每隔10s设置锁为30s)
3.提供简单实用的方法,不用自己维护细节 - 基于zookeeper
原理:实现基础-有序节点
1.虚拟有序节点
2.监听事件
在/*/目录下创建虚拟有序节点,节点序号最小则为获取锁成功,其他节点监听各自上一个节点的删除事件。
如果当前节点为锁节点,释放时会删除当前虚拟节点,并唤醒线程自检,如果拥有的节点为当前序号最小,则获取锁,类推。
适用的工具:Curator
几种分布式锁的实现方式记录
最新推荐文章于 2024-06-20 20:20:21 发布