应用场景介绍
配置中心 分布式锁 分布式序列生成器
Curator
DistributedLock
DistributedCounter
DistributedBarrier
DistributedQueue
Transaction Watcher
主要应用:
配置中心
分布式锁
分布式序列生成器
引入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cc</groupId>
<artifactId>springboot-zookeeper-curator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>pringboot-zookeeper-curator</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.简单应用
package com.cc.springbootzookeepercurator;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import java.nio.charset.Charset;
/**
* Created by CarlosXiao on 2018/7/29.
*/
@Slf4j
public class CuratorTest {
public static final String ZK_HOST = "192.168.13.51:2182,192.168.13.51:2183,192.168.13.51:2184,192.168.13.51:2185";
public static void main(String [] args) throws Exception {
//1、建立连接
// 重试5次,每次间隔1秒
RetryPolicy retry1 = new ExponentialBackoffRetry(1000, 5);
// 重试5次,每次间隔5秒
//RetryPolicy retry2 = new RetryNTimes(5, 5000);
CuratorFramework client = CuratorFrameworkFactory
.builder()
.connectString(ZK_HOST)
.connectionTimeoutMs(5000)
.retryPolicy(retry1)
.build();
client.start();
log.info(client.getState().name());
// createNode(client);
// update(client);
delete(client);
client.close();
}
/**
* 创建节点
* @param client
*/
public static void createNode(CuratorFramework client) {
try {
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath("/curator/testcreate", "test_create".getBytes(Charset.defaultCharset()));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void update(CuratorFramework client) throws Exception {
Stat stat = new Stat();
String path = "/curator/testcreate";
byte [] data = client.getData().storingStatIn(stat).forPath(path);
log.info("修改前的值: {}", new String(data, Charset.defaultCharset()));
client.setData()
.withVersion(stat.getVersion())
.forPath(path, "update".getBytes(Charset.defaultCharset()));
data = client.getData().forPath(path);
log.info("修改后的值: {}", new String(data, Charset.defaultCharset()));
}
public static void delete(CuratorFramework client) {
String path = "/curator/testcreate";
try {
client.delete()
.guaranteed()
.deletingChildrenIfNeeded()
.withVersion(-1)
.forPath(path);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.Zookeeper Curator 高级应用
监听Watcher实现:功能:当一个应用程序节点发生改变通知其他节点改变就是用Watcher机制实现
对监听的节点进行其他操作,都会进去对应方法,如下对/curator下的子节点进行增加,修改,删除操作时,都能进入对应代码区域再进行相应操作
NodeCache:监听当前节点
PathChildrenCache:监听子节点用法如下:
package com.cc.springbootzookeepercurator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.*;
import java.nio.charset.Charset;
/**
* 事务操作
*/
public class WatcherExamples {
private static CuratorFramework client = ClientFactory.newClient();
public static void main(String[] args) {
try {
client.start();
//节点监听需要用repices包中的NodeCache来完成
final String path = "/curator/watcher";
final NodeCache cache = new NodeCache(client,path);
cache.start();
cache.getListenable().addListener(() -> {
byte[] ret = cache.getCurrentData().getData();
System.out.println("当前节点" + path +"=:"+ new String(ret));
});
//在父节点进行监听
final String pPath = "/curator";
PathChildrenCache pcCache = new PathChildrenCache(client,pPath,true);
pcCache.start();
pcCache.getListenable().addListener((curatorFramework, pathChildrenCacheEvent) -> {
switch (pathChildrenCacheEvent.getType()){//子节点的事件类型
//通过pathChildrenCacheEvent,可以获取到节点相关的数据
case CHILD_ADDED:
System.out.println("增加节点" + pathChildrenCacheEvent.getData().getPath()
+ "=" +new String(pathChildrenCacheEvent.getData().getData(),Charset.defaultCharset()) );
break;
case CHILD_REMOVED:
System.out.println("删除节点"+pathChildrenCacheEvent.getData().getPath());
break;
case CHILD_UPDATED:
System.out.println("更新节点" + pathChildrenCacheEvent.getData().getPath()
+ "=" +new String(pathChildrenCacheEvent.getData().getData(), Charset.defaultCharset()));
break;
default:
break;
}
});
Thread.sleep(Integer.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.cc.springbootzookeepercurator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class ClientFactory {
public static CuratorFramework newClient() {
String connectionString = "192.168.13.51:2182,192.168.13.51:2183,192.168.13.51:2184,192.168.13.51:2185";
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3);
return CuratorFrameworkFactory.newClient(connectionString, retryPolicy);
}
}
3.事务中应用实例
传统的关系型数据库中的事务会非常慢,分布式事务能提升性能
使用CuratorTransaction操作事务:
forPath可以继续一直下去,提交后会一起成功或者失败
package com.cc.springbootzookeepercurator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.api.transaction.CuratorTransaction;
import org.apache.curator.framework.api.transaction.CuratorTransactionResult;
import org.apache.curator.utils.CloseableUtils;
import java.util.Collection;
/**
* 事务操作
*/
public class TransactionExamples {
private static CuratorFramework client = ClientFactory.newClient();
public static void main(String[] args) {
try {
client.start();
// 开启事务
CuratorTransaction transaction = client.inTransaction();
Collection<CuratorTransactionResult> results = transaction.create()
.forPath("/b", "some data".getBytes()).and().setData()
.forPath("/b", "other data".getBytes())
.and().commit();
for (CuratorTransactionResult result : results) {
System.out.println(result.getForPath() + " - " + result.getType());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseableUtils.closeQuietly(client);
}
}
}
4.分布式计数器
单机版本,及单个服务器jvm使用AtomicInteger实现计数:可以用在分布式系统中订单或者序列生成自增编号等,
分布式中使用DistributedAtomicInteger
package com.cc.springbootzookeepercurator.atomic;
import com.cc.springbootzookeepercurator.ClientFactory;
import com.google.common.collect.Lists;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.atomic.AtomicValue;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicInteger;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
import org.apache.curator.retry.RetryNTimes;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 这个类我没能运行出期待的结果来,谁检查一下我的代码?
*/
public class DistributedAtomicIntegerExample {
private static CuratorFramework client = ClientFactory.newClient();
private static final String PATH = "/counter";
public static DistributedAtomicInteger counter;
static {
client.start();
counter = new DistributedAtomicInteger(client, PATH, new RetryNTimes(3, 1000));
}
public static void main(String[] args) {
final Random rand = new Random();
List<DistributedAtomicLong> examples = Lists.newArrayList();
ExecutorService service = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; ++i)
{
final DistributedAtomicLong count = new DistributedAtomicLong(client, PATH, new RetryNTimes(10, 10));
examples.add(count);
Callable<Void> task = () -> {
try
{
Thread.sleep(1000 + rand.nextInt(10000));
AtomicValue<Long> value = count.increment();
System.out.println("修改成功: " + value.succeeded());
if (value.succeeded())
{
System.out.println("修改之前的值:" + value.preValue() + " | 修改之后的值:" + value.postValue());
}
}
catch (Exception e) {
e.printStackTrace();
}
return null;
};
service.submit(task);
}
service.shutdown();
try {
service.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
client.close();
}
}
5.分布式锁
InterProcessReadWriteLock:读写锁
读写锁,排他锁,互斥锁,
package com.cc.springbootzookeepercurator.lock;
import com.cc.springbootzookeepercurator.ClientFactory;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
/**
* Created by CarlosXiao on 2018/7/29.
*/
public class DistributedLockTest {
static CuratorFramework client = ClientFactory.newClient();
public static void main(String[] args) throws Exception {
client.start();
InterProcessReadWriteLock readWriteLock = new InterProcessReadWriteLock(client, "/read-write-lock");
//读锁
final InterProcessMutex readLock = readWriteLock.readLock();
//写锁
final InterProcessMutex writeLock = readWriteLock.writeLock();
try {
readLock.acquire();
System.out.println(Thread.currentThread() + "获取到读锁");
new Thread(() -> {
try {
//在读锁没释放之前不能读取写锁。
writeLock.acquire();
System.out.println(Thread.currentThread() + "获取到写锁");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
writeLock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
//停顿3000毫秒不释放锁,这时其它线程可以获取读锁,却不能获取写锁。
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
} finally {
readLock.release();
}
Thread.sleep(10000);
client.close();
}
}