分布式锁的类型
mysql实现分布式锁
1.数据库建立锁表
数据库属性:
主键,方法名入参,主机信息线程名字(保证)。备注。(方法名入参建立唯一性索引)
实现方式:当需要锁定方法时,将方法名和入参insert进去即可,解锁时删除该条记录即可。
弊端:
1.不能作为阻塞锁来使用。
2.锁没有失效时间,删除锁出现问题的时候,其他线程无法获取锁,这个方法将会一直锁住。
3.数据库作为单点系统,当出现问题的时候,导致整个系统出现不可运行。
弊端解决方案:
1.不能作为阻塞锁来使用:加锁里面做一个while循环获得锁再跳出
2.锁没有失效时间:做定时任务。
3.数据库单点不可靠:做主备,服务降级等。
2.数据库建立排他锁
数据库属性:
主键,方法名入参,主机信息线程名字(保证),备注。(方法名入参建立唯一性索引)
实现方式:利用数据库的排他锁实现分布锁,加锁:select * from method_lock where method =xx for update(自动提交关闭)
解锁:connection.commit();
这样就比较优雅的解决了阻塞问题,判断是否有这条记录,有的话继续等待,或者出现问题的话处于一直阻塞的状态,成功的话就直接返回了,完事解锁就成
会出现的问题:
1.当数据量比较小的时候,数据库的执行策略判断全表扫描会比走索引快时候,这是就不是行级锁了,而是走表级锁了,这时就出现的问题就大了,所有他有一定风险。
2.但一直没执行解锁操作的时候线程就一直占用着connection,然后数据库连接数局满了。
缓存实现分布式锁
使用redis实现分布式锁
使用redis实现分布式锁是一个比较大家用到比较多的方式
实现方式:使用jedis来向redis里面set数据:具体参数,key(唯一性的代表锁),requestId(value放请求Id,这样能保证开锁解锁都是同一个人),加锁逻辑是,当key不存在时,才进行set操作,若key已经存在,则不做任何操作。同时set过期时间,这里需要注意的是set数据可set过期时间是同一个操作,防止set完数据出现程序崩溃产生死锁问题。
解锁:为了用key获取value查看request是否一致,一致则解锁,但是查询,对比,删除锁,这一些为了保证原子信记得加事务。
不好的地方:过期时间时间不好控制,容易出现垃圾锁的问题或者锁解了事务还没完。
好的地方:性能好,搭建简单。
zk实现分布式锁
使用zookeeper实现分布式锁
由于自己本身没有使用过zk实现分布式锁,这里看到一个百家号写的比较好,给上链接。
https://baijiahao.baidu.com/s?id=1593258103626631655&wfr=spider&for=pc