分布式场景下,锁的实现以及相应的优缺点
选型考虑点:
1、性能:锁的获取和释放的性能要好;
2、原子性:判断和执行锁的获取,必须是原子性的。否则可能多个请求都可以获取到锁;
3、死锁:网络中断或者宕机导致无法释放锁时,锁必须要清楚,否则死锁。
4、可重入性:同一个线程可以多次获取同一把锁。比如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法,而无需重新获得锁;
5、两种锁:阻塞锁和非阻塞锁。阻塞锁即没有获取到锁,则继续等待获取锁;非阻塞锁即没有获取到锁后,不继续等待,直接返回锁失败。
实现方式:数据库锁、redis、zk
一、数据库锁的实现方式:
1、基于mysql的锁表:该实现方式完全依靠数据库唯一索引来实现,当想要获得锁时,即向数据库中插入一条记录,释放锁时就删除这条记录(通过控制表的增删来操作)。这种方式存在以下几个问题。
优势:实现简单
劣势:(1)、死锁:锁没有失效时间,解锁失败会导致死锁,其他线程无法再获取到锁,因为唯一索引insert都会返回失败
(2)、只能是非阻塞锁。insert失败则报错,无法进入队列重试。
(3)、不可重入。同一个线程没有释放锁之前无法获取该锁。
2、采用版本号的乐观锁。根据版本号来判断更新之前有没有其他线程更新过,如果被更新过,则获取锁失败。
优势:实现简单;
劣势:(1)、性能:依靠数据库的操作,性能差。(tps挺多五千)
(2)、原子性:为保证原子性,依赖数据库的悲观锁,导致性能降低;
(3)、不可重入。
二、redis锁
三、ZK锁