使用zookeeper实现分布式锁
使用zk实现分布式锁原理机制:
1.定义锁:在通常的Java开发编程中,有两种常⻅的⽅式可以⽤来定义锁,分别是synchronized机制和JDK5提供的ReentrantLock。然⽽,在ZooKeeper中,没有类似于这样的API可以直接使⽤,⽽是通过 ZooKeepe上的数据节点来表示⼀个锁,例如/base/order_1节点就可以被定义为⼀个锁
2.获取锁:在需要获取排他锁时,所有的客户端都会试图通过调⽤ create()接⼝,在/base节点下创建临时⼦节点/base/order_1。ZooKeeper会保证在所有的客户端中,最终只有⼀个客户端能够创建成功,那么就可以认为该客户端获取了锁。同时,所有没有获取到锁的客户端就需要到/base 节点上注册⼀个⼦节点/base/order_1变更的Watcher监听,以便实时监听到lock节点的变更情况3.释放锁:/base/order_1是⼀个临时节点,因此在以下两种情况下,都有可能释放锁。当前获取锁的客户端机器发⽣宕机,那么ZooKeeper上的这个临时节点就会被移除。正常执⾏完业务逻辑后,客户端就会主动将⾃⼰创建的临时节点删除。⽆论在什么情况下移除了lock节点,ZooKeeper都会通知所有在/base节点上注册了⼦节点/base/order_1变更Watcher监听的客户端。这些客户端在接收到通知后,再次重新发起分布式锁获取,即重复获取锁过程。
引入依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.0.0</version>
</dependency>
初始化zk链接
@Configuration
public class CuratorConfig {
@Bean(initMethod = "start")
CuratorFramework curatorFramework(){
RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("ip:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(exponentialBackoffRetry)
.namespace("base") // 独立的命名空间 /base
.build();
return client;
}
}
使用curator来实现
@Autowired
private CuratorFramework curatorFramework;
/**
* 分布式锁测试实例
*
* @return 结果
*/
public boolean recharge(Integer userId, Integer orderId){
boolean result = false;
InterProcessMutex lock = new InterProcessMutex(curatorFramework, "/order_" + orderId);
try{
lock.acquire();
result = accountDomainService.recharge(userId,orderId);
}catch(Exception e){
result=false;
throw new RuntimeException("执行失败");
}finally {
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
使用jemter测试
开了500个线程
看数据库可以知道balance只增加了10,说明500个线程只有一个线程成功增加10,其他线程在发现订单的status是1后就不增加了,分布式锁实现了,也可以自己手动写个实现类,用开篇的思路就可以