场景
注册中心
因为是树结构
且能动态感知到服务上线下线
提供者注册子节点
消费者监听父节点
分布式节点名称
dns域名解析
服务创建后就创建zk临时节点
分布式ID生成器
- 有序节点 少量低并发(zk底层是同步按顺序生成的)
- 维护雪花算法的一部分内容
雪花算法 是4部分组成:
保留位
时间戳 : 精确到毫秒
机器id : zk维护
序列号
分布式锁
高可用且并发量不太高的情况下
Redis可能有琐失效的问题,主节点加锁后挂掉锁就丢失了
zk是主节点会半数同步从节点后回复客户端
加锁:
创建临时节点
获取锁失败:
监听节点,并等待,可以借助锁的加锁和解锁实现
但是这样唤醒可能会出现线程饥饿问题
可以借助临时有序节点实现
加锁线程都创建有序的临时节点
然后比较最小的节点先获取锁
获取锁失败的线程:
监听前边的临时节点,如:02监听01,03监听02,01监听00
如果临时节点解锁后就一次唤醒节点
Curator框架提供了可重入的互斥锁
和redis锁有不同的是zk锁不能设置超时时间,但是zk锁没有如果机器意外挂掉,锁还要等待超时时间到了才能取消的问题,因为临时节点的特性
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>5.2.0</version>
</dependency>
//加锁解锁
private void lockBizDue() {
InterProcessMutex lock = null;
try {
String lockKey = "lock/biz_code";
//System.out.println("加锁");
lock = this.lock(lockKey);
this.bizDue();
} catch (Exception e) {
System.out.println("业务处理异常-异常为:" + Throwables.getStackTraceAsString(e));
} finally {
try {
if (lock != null) {
lock.release();
}
} catch (Exception e) {
System.out.println("解锁异常-异常为:" + Throwables.getStackTraceAsString(e));
}
}
}
//业务处理
private void bizDue() {
System.out.println("业务处理");
this.count ++;
}
//创建zkClient
private void buildCurator() {
CuratorFramework curator = CuratorFrameworkFactory.builder()
//.aclProvider(aclProvider)//防止其它操作误操作节点,加上权限限制
//.authorization(authScheme, id.getBytes())//防止其它操作误操作节点,加上权限限制
.connectString(connectString)//zk连接串
.sessionTimeoutMs(Integer.parseInt(sessionTimeoutMs))//session 超时时间
.connectionTimeoutMs(Integer.parseInt(connectionTimeoutMs)).defaultData("0".getBytes())//连接zk超时时间
.retryPolicy(new ExponentialBackoffRetry(Integer.parseInt(baseSleepTimeMs), Integer.parseInt(maxRetries)))//连接zk重试次数以及重试间隔时间
.maxCloseWaitMs(Integer.parseInt(maxCloseWaitMs))//关闭连接等待时间
.build();
curator.start();
this.curatorFramework = curator;
System.out.println("client已完成初始化");
}
//创建可重入锁
private InterProcessMutex lock(String lockKey) throws Exception {
//临时顺序节点的根节点
String lockPath = "/lock1/" + lockKey;
//申明可重入锁
InterProcessMutex lock = new InterProcessMutex(curatorFramework, lockPath);
//这里的acquire方法是阻塞方法,超时时间是3分钟
if (lock.acquire(3, TimeUnit.MINUTES)) {
//System.out.println("节点列表>>>" + lock.getParticipantNodes());
Stat stat = curatorFramework.checkExists().forPath(lockPath);
if (null != stat) {
//System.out.println(lockPath + "节点信息>>>" + JSON.toJSONString(stat));
}
}
//返回lock,说明成功获取到锁
return lock;
}