分布式锁
分布式锁
- 单体应用,所有请求都会分配到当前服务器的JVM内部,然后映射为操作系统的线程进行处理,这个共享变量只是这个JVM内部的一快空间。
- 单机环境可java自带的apiReentrantLock或Synchronize进行互斥控制。
集群要部署到多个服务器,变量在多个JVM的内存区域,不具备可见性。需要跨JVM的互斥操作。
分布式锁条件
分布式环境下,一个方法同一时间只能被一个机器的一个线程执行。
- 高可用。
- 高性能。
- 可重入。
- 锁失效机制,防止死锁。
-
三种实现方式
分布式C一致性A可用性P分区容错性理论,只能满足两项。
- 基于数据库的排他锁。
- 新建表,插入唯一性约束
- 新建表,更改字段
- 缺:数据库单点,没有失效时间,非阻塞,非可重入。
- 基于缓存(Redis)实现。
- Boolean lock = setIfAbsent(lockKey,LOCK);//获取锁
- expire(lockKey,1,TimeUnit.MINUTES);//过期时间
- 缺:主从下,master获取锁,master宕机,slaver晋升master,安全失效。
- ZK实现。
- ZK数据存储结构类似树,由节点组成,
- 持久节点:默认,节点客户端与zk断开后,依旧存在。
- 持久顺序节点:创建时,根据时间给节点进行编号。
- 临时节点:和持久节点相反,断开后消失。
- 临时顺序节点:结合临时和顺序节点的特点。
- zk分布式锁原理:用到了临时顺序节点。
- 获取锁:创建持久节点ParentLock,第一个客户端想要获取锁,需要在ParentLock节点下创建一个临时顺序节点Lock1,之后客户端查找临时顺序节点并排序,若式第一个节点就获取锁。客户端2获取同理,若排序不是第一个,客户端2向前面节点注册Watcher监听,这是意味着客户端2枪锁失败,进入等待。
- 释放锁
- 情景1,任务完成,客户端调用删除节点指令。
- 情景2,客户端崩溃,断开与zk的连接,根据临时节点特性自动删除。若有watcher,接到通知。
- 缺点:性能没有缓存高,并发问题,由于网络抖动导致的session中断,zk会以为客户端挂了让其他获取锁,导致问题(这个问题不常见因心跳重试机制)。
- ZK数据存储结构类似树,由节点组成,
分布式锁(zk应用)
来源:com/zking/dp/sales/core/management/util/RedisLock.java:146
- 思路
- 获得lock
- 用了setnx命令,缓存锁。
- redis缓存的key是锁的key,共享,value是到期时间(注意:这里把过期时间放在value了,没有时间上设置其超时时间)
- 执行过程
- 通过setnx尝试设置某key的值,成功(当前没有这个锁)则返回,获取到锁。
- 锁已经存在则获取锁的到期时间,和当前时间比较,超时的话,则设置新的值。