分布式锁

137 阅读2分钟

关于分布式锁的一些想法:

尽量不用RedLock,建立在【时钟正确】的基础之上,很难搞。

还是会优先考虑使用redis的主从+哨兵模式,实现分布式锁。

1 在极端情况下会失效,但他可以最大程度把并发请求阻挡在最外层,减轻操作资源层的压力,利用fencing token /数据库层来保证最终的稳定性。

1 基于数据库

1.1 基于数据库唯一索引

加锁添加数据,解锁删除数据。

问题:并发量下性能问题,可重入,数据库单点,无失效时间。

1.2 基于数据库排他锁

在查询语句后面增加for update,数据库会在查询过程中(须通过唯一索引查询)给数据库表增加排他 锁,我们可以认为获得排它锁的线程即可获得分布式锁,通过 connection.commit() 操作来释放锁。

注意:innodb的行锁在一定条件下(非索引查询会锁全表),会失去效果,使用表锁。

问题:并发量下性能问题,可重入,数据库单点,无失效时间,有可能使用表锁。

基于分布式缓存

基于缓存的在性能上会好很多。 setNx(); 基于Redlock做分布式锁

Redlock是Redis的作者antirez给出的集群模式的Redis分布式锁,它基于N个完全独立的Redis节点(通常情况下N可以设置成5)。

优点:

  • 性能好

缺点:

  • 实现中需要考虑的因素太多
  • 通过超时时间来控制锁的失效时间并不是十分的靠谱。

基于Zookeeper

利用了zookper的墙一致性。

image.png

为什么加锁之前需要拿到所有的节点,判断自己是否是第一个?而不是直接判断是否有上一个节点存在即可?

-因为如果master宕机了,也是一个也拿不到。

为什么不只存在一个节点,然后创建失败就阻塞呢?

-这是非公平锁的方式。

排他锁和共享锁,以及如何解决羊群效应。

优势: 

1 不用考虑过期时间,利用临时顺序节点实现

2 本身就存在watch机制,避免“羊群效应”,实现乐观锁

缺点:

1 性能不好

2 部署和运维成本高

3 异常场景(长时间GC)下session失效,导致锁被错误释放

排他锁(非公平锁)

排他锁核心是保证当前有且仅有一个事务获得锁,并且锁释放之后,所有正在等待获取锁的事务都能够被通知到。

共享锁(公平锁)