1

在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。数据只适合在并发比较小的情况下用。


大军
847 声望183 粉丝

学而不思则罔,思而不学则殆


引用和评论

1 篇内容引用
0 条评论