需求
- 互斥性:和我们本地锁一样互斥性是最基本,但是分布式锁需要保证在不同节点的不同线程的互斥。
- 可重入性:同一个节点上的同一个线程如果获取了锁之后那么也可以再次获取这个锁。
- 锁超时:和本地锁一样支持锁超时,防止死锁。
- 高效,高可用:加锁和解锁需要高效,同时也需要保证高可用防止分布式锁失效,可以增加降级。
- 支持阻塞和非阻塞:和ReentrantLock一样支持lock和trylock以及tryLock(long timeOut)。
- 安全性:锁只能被持有者删除
常见的几种方式
- MySql
- 优点:理解起来简单,不需要维护额外的第三方中间件(比如Redis,Zk)。
- 缺点:实现起来较为繁琐,需要自己考虑锁超时,加事务等等,性能局限于数据库,一般对比缓存来说性能较低,对于高并发的场景并不是很适合。
- Apache ZooKeeper
- 优点:不需要关心锁超时时间,实现起来有现成的第三方包,比较方便,并且支持读写锁,ZK获取锁会按照加锁的顺序,所以其是公平锁,对于高可用利用ZK集群进行保证。
- 缺点:ZK需要额外维护,增加维护成本,性能和Mysql相差不大,依然比较差,并且需要开发人员了解ZK是什么。
- Redis
- 优点:对于Redis实现简单,性能对比ZK和Mysql较好,如果不需要特别复杂的要求,那么自己就可以利用setNx进行实现,如果自己需要复杂的需求的话那么可以利用或者借鉴Redission,对于一些要求比较严格的场景来说的话可以使用RedLock。
- 缺点:需要维护Redis集群,如果要实现RedLock那么需要维护更多的集群。
取舍选择:redis
- zk和DB在高并发的场景下可能会有性能问题,通过redis实现分布式锁不管是从实现难度和性能方面都比较合适
- 避免维护zk集群
增强(可选,会增加复杂度):
- 使用集群进行加锁(多于集群过半数量)