分布式锁原理及实现方式

     来自:http://blog.csdn.net/zxp_cpinfo/article/details/53692922


分布式锁应该达到的效果:

1.可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行

2.这把锁是一个可重入锁(避免死锁)

3.最好是阻塞锁(根据业务需要考虑是否需要这一条)

4.有高可用的获取锁和释放锁功能

5.获取锁和释放锁的性能要好


http://www.hollischuang.com/archives/1716

方案:

一、基于数据库实现分布式锁

基于数据库表。

要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现。

当需要锁住某个方法或资源时,就在该表中增加一条记录,想要释放锁的时候就删除这条记录

问题:

1.这把锁依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用

2.这把锁没有失效时间,一旦解锁操作失败,会导致锁记录一直在数据库中,其他线程无法再获得锁

3.这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错,没有获得锁的线程并不会进入排队队列,想要再次获得锁就要再次触发获得锁操作。

4,这把锁是非重入的,同一个线程没有释放锁之前无法在获得该锁,因为数据已经存在了。


解决:

1.数据库是单点?搞两个数据库,数据之前双向同步,一旦挂掉迅速切换到备库上。

2.没有失效时间?做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。

3.非阻塞?搞一个while循环,直到insert成功再返回

4.非重入的?在数据库中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查询的话,直接把锁分配给他就可以了。

基于数据库排他锁:

除了可以通过增删操作数据库中的记录以外,其实还可以借助数据中自带的锁来实现分布式的锁。

在查询语句后面增加for update语句,数据库会在查询过程中给数据表增加排他锁(innodb引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁)

使用数据库来实现分布式锁的方式,这两种方式都是依赖数据库的一张表,一种是通过表中的记录的存在情况确定当前是否有锁存在,另外一种是通过数据库的排他锁来实现分布式锁。


二、基于Redis

(自己参考Redis官网总结)

最低保障的分布式锁:

1.安全属性:独享(相互排斥),在任意一个时刻,只有一个客户端持有锁

2.活性A:无死锁,即便持有锁的客户端崩溃或者网格被分裂,锁仍然可以被获取

3.活性B:容错,只要大部分Redis节点都活着,客户端就可以获取和释放锁。

大部分Redis的分布式锁和实现方法

最简单方式是在Redis中创建一个key,这个key有一个失效时间(TTL),以保证锁最终会被自动释放掉,当客户端释放资源(解锁)的时候,会删除这个key

但是会存在一个问题:严重的单点失败问题。如果Redis挂掉了增加一个slave节点也是行不通的,这样不能实现资源独享,Redis的主从同步通常是异步的。

主从结构存在的明显竟态:

1.客户端A从master获取锁

2.在master将同步锁同步到slave之前,master宕掉了

3.slave节点被晋级为master节点

4.客户端B取得了同一个资源被客户端A已经获取到的另一个锁,安全失效。


正确方法:


获取锁使用命名:

set resource_name my_random_value NX PX 3000

这个命令仅在不存在key的时候执行成功(NX选项),并且这个key有一个30秒的自动失效时间(PX)

属性,这个key的值是my_random_value(一个随机值),这个值所有的客户端必须是唯一的,所有同一key的获取者这个值都不能一样。

value值必须是随机数主要是为了更安全的释放锁,释放锁的时候使用脚本告诉Redis:只要key存在并且存储的值和我指定的值一样才能告诉我删除成功

if redis.call("GET",KEYS[1]) == ARGV[1] then

   return redis.call("del",KEYS[1])

else

  return 0

end

三、zookeeper


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值