共计 1159 个字符,预计需要花费 3 分钟才能阅读完成。
在 jvm 中,咱们能够通过 synchronized 或者 cas 的 lock 加锁。又有单机的性能太差,无奈适应高并发的需要,所以咱们做了集群,此时 jvm 是无法控制其余 jvm 的锁的,这个时候只能分布式锁解决。分布式锁的实质,就是互斥,被 A 霸占了资源,BCDEF 等都不能用,把并行的操作,转为串行。
数据库
主键或惟一索引
咱们晓得,主键和惟一索引是不能反复的,所以咱们能够利用这个做到资源的互斥。通过 insert 语句,insert into table VALUES(id,col1,col2)
,如果插入胜利,阐明拿到了锁,如果插入失败,报 Duplicate entry...key 'PRIMARY'
的谬误,阐明锁曾经被拿到了。拿到锁的利用,操作实现,只须要删除这个 id 就能够开释锁了,其余利用就能够 insert 胜利拿到锁。
因为 insert 和 delete 是两个操作,如果 delete 失败,则锁无奈开释。所以插入的时候还要记录插入的工夫,而后跑一个定时工作,看他曾经多久没开释锁了,如果工夫超过设定的阈值,则阐明他删除失败,把这个记录删除开释锁。这边又引入了一个问题,阈值要怎么设置?设置长了,会导致其余利用长时间获取不到锁,设置短了,获取锁的利用还没执行完,锁就生效了,而后其余利用由获取到这个锁,达不到对资源互斥的成果。
乐观锁
次要是通过 version 来判断。update table set col1=val,version=v1 where version=v2
,先从数据库取出 version,再执行下面的语句,如果执行胜利,阐明拿到锁。乐观锁和主键的长处是他不须要开释锁。然而在大量的并发下,频繁的操作这个表,可能会导致数据库的不可用。
乐观锁
借助 mysql 数据库的 FOR UPDATE
,FOR UPDATE 是一种行级锁,又叫排它锁。FOR UPDATE 仅实用于 InnoDB,且必须在事务处理模块(BEGIN/COMMIT) 中能力失效。用法如下:
# 开始事务
begin;
#乐观锁
select col1 from table where id=1 for update;
#解决其余业务
#...
#提交事务
commit;
乐观锁尽管保障了串行化,然而每次申请都会申请锁,很容易因为大量的申请导致数据库的不可用。
redis
redis – 分布式锁
zookeeper
zookeeper 之分布式锁
etcd
比照
从性能上来说,redis>etcd>zookeeper> 数据库,从 cap 模型来说,redis 是 ap 模型,zookeeper、etcd 是 cp 模型,数据库是 ac 模型(做主从就是 ap)。
从业务来说,比方对钱的操作,须要强一致性的,那要用 cp 模型的分布式锁,比方 zookeeper,etcd。如果不须要强一致性的,容许偶然的数据问题,那能够用 redis。数据只适宜在并发比拟小的状况下用。