关于分布式锁的一些想法:
尽量不用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的墙一致性。
为什么加锁之前需要拿到所有的节点,判断自己是否是第一个?而不是直接判断是否有上一个节点存在即可?
-因为如果master宕机了,也是一个也拿不到。
为什么不只存在一个节点,然后创建失败就阻塞呢?
-这是非公平锁的方式。
排他锁和共享锁,以及如何解决羊群效应。
优势:
1 不用考虑过期时间,利用临时顺序节点实现
2 本身就存在watch机制,避免“羊群效应”,实现乐观锁
缺点:
1 性能不好
2 部署和运维成本高
3 异常场景(长时间GC)下session失效,导致锁被错误释放
排他锁(非公平锁)
排他锁核心是保证当前有且仅有一个事务获得锁,并且锁释放之后,所有正在等待获取锁的事务都能够被通知到。