ZooKeeper 之Apache Curator 客户端使用

2023-11-05

ZooKeeper 原生不足之处:

  • 超时重连,不支持自动,需要手动操作
  • Watch注册一次后会失效
  • 不支持递归创建节点

 Apache Curator 

apache的开源项目,解决watcher注册一次就失效的问题,api更加简单易用,提供更多解决方案并且实现简单:如分布式锁

Maven 添加 Apache Curator 依赖

        <!--zookeeper相关-->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.6</version>
        </dependency>

zk基本操作

zk命名空间以及创建节点,节点的增删改查

import java.util.List;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.Stat;

public class CuratorOperator {

	public CuratorFramework client = null;
	public static final String zkServerPath = "192.168.254.130:2181";
	/**
	 * 实例化zk客户端
	 */
	public CuratorOperator() {
		/**
		 * curator链接zookeeper的策略:RetryNTimes
		 * n:重试的次数
		 * sleepMsBetweenRetries:每次重试间隔的时间
		 */
		RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
		
		client = CuratorFrameworkFactory.builder()
				.connectString(zkServerPath)
				.sessionTimeoutMs(10000).retryPolicy(retryPolicy)
				//命名空间之后创建的节点都会在workspace工作空间里面
				.namespace("workspace").build();
		client.start();
	}
	/**
	 *
	 * @Description: 关闭zk客户端连接
	 */
	public void closeZKClient() {
		if (client != null) {
			this.client.close();
		}
	}
	
	public static void main(String[] args) throws Exception {
		// 实例化
		CuratorOperator cto = new CuratorOperator();
		boolean isZkCuratorStarted = cto.client.isStarted();
		System.out.println("当前客户的状态:" + (isZkCuratorStarted ? "连接中" : "已关闭"));
		
		// 创建节点
		String nodePath = "/bushro/demo";
		byte[] data = "data".getBytes();
		cto.client.create().creatingParentsIfNeeded()
			.withMode(CreateMode.PERSISTENT)
			.withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)//默认的权限"world", "anyone"
			.forPath(nodePath, data);
		
		 更新节点数据
		byte[] newData = "newdata".getBytes();
		cto.client.setData().withVersion(0).forPath(nodePath, newData);

		// 删除节点
		cto.client.delete()
				  .guaranteed()					// 如果删除失败,那么在后端还是继续会删除,直到成功
				  .deletingChildrenIfNeeded()	// 如果有子节点,就删除
				  .withVersion(0)
				  .forPath(nodePath);
		
		// 读取节点数据
		Stat stat = new Stat();
		byte[] data = cto.client.getData().storingStatIn(stat).forPath(nodePath);
		System.out.println("节点" + nodePath + "的数据为: " + new String(data));
		System.out.println("该节点的版本号为: " + stat.getVersion());
		
		// 查询子节点
		List<String> childNodes = cto.client.getChildren()
											.forPath(nodePath);
		System.out.println("开始打印子节点:");
		for (String s : childNodes) {
			System.out.println(s);
		}
			
		// 判断节点是否存在,如果不存在则为空
		Stat statExist = cto.client.checkExists().forPath(nodePath + "/abc");
		System.out.println(statExist);
		
		Thread.sleep(100000);
		
		cto.closeZKClient();
		boolean isZkCuratorStarted2 = cto.client.isStarted();
		System.out.println("当前客户的状态:" + (isZkCuratorStarted2 ? "连接中" : "已关闭"));
	}
	
	public final static String ADD_PATH = "/super/imooc/d";
	
}

watch与acl的操作

一次注册多次监听

为节点添加watch事件

		// 为节点添加watcher
		//NodeCache: 监听数据节点的变更,会触发事件
		final NodeCache nodeCache = new NodeCache(cto.client, nodePath);
		// buildInitial : 初始化的时候获取node的值并且缓存
		nodeCache.start(true);
		if (nodeCache.getCurrentData() != null) {
			System.out.println("节点初始化数据为:" + new String(nodeCache.getCurrentData().getData()));
		} else {
			System.out.println("节点初始化数据为空...");
		}
		nodeCache.getListenable().addListener(new NodeCacheListener() {
			public void nodeChanged() throws Exception {
				if (nodeCache.getCurrentData() == null) {
					System.out.println("空");
					return;
				}
				String data = new String(nodeCache.getCurrentData().getData());
				System.out.println("节点路径:" + nodeCache.getCurrentData().getPath() + "数据:" + data);
			}
		});

为子节点添加watch事件

		// 为子节点添加watcher
		// PathChildrenCache: 监听数据节点的增删改,会触发事件
		String childNodePathCache =  nodePath;
		// cacheData: 设置缓存节点的数据状态
		final PathChildrenCache childrenCache = new PathChildrenCache(cto.client, childNodePathCache, true);
		/**
		 * StartMode: 初始化方式
		 * POST_INITIALIZED_EVENT:异步初始化,初始化之后会触发事件(比较好)
		 * NORMAL:异步初始化
		 * BUILD_INITIAL_CACHE:同步初始化
		 */
		childrenCache.start(StartMode.POST_INITIALIZED_EVENT);

		List<ChildData> childDataList = childrenCache.getCurrentData();
		System.out.println("当前数据节点的子节点数据列表:");
		for (ChildData cd : childDataList) {
			String childData = new String(cd.getData());
			System.out.println(childData);
		}

		childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
			public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
				if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)){
					System.out.println("子节点初始化ok...");
				}

				else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
					String path = event.getData().getPath();
					System.out.println("添加子节点:" + event.getData().getPath());
					System.out.println("子节点数据:" + new String(event.getData().getData()));

				}else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){
					System.out.println("删除子节点:" + event.getData().getPath());
				}else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
					System.out.println("修改子节点路径:" + event.getData().getPath());
					System.out.println("修改子节点数据:" + new String(event.getData().getData()));
				}
			}
		});

watcher统一配置

例如创建一个存放redis的配置文件节点,里面放入相关操作的json数据如
{“type”:“add”,“url”:“ftp://192.168.254.130/config/redis.xml”,“remark”:“add”}
{“type”:“update”,“url”:“ftp://192.168.254.130/config/redis.xml”,“remark”:“update”}
{“type”:“delete”,“url”:"",“remark”:“delete”}
在程序中我们可以把节点数据转成实体类,根据type的类型来判断进行相应的操作,当zookeeper集群中监听到变化,每台机子就去下载最新的配置文件这样就不用一台一台机子的修改过去,节省时间。
 

public class Client1 {

	public CuratorFramework client = null;
	public static final String zkServerPath = "192.168.254.130:2181";

	public Client1() {
		RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
		client = CuratorFrameworkFactory.builder()
				.connectString(zkServerPath)
				.sessionTimeoutMs(10000).retryPolicy(retryPolicy)
				.namespace("workspace").build();
		client.start();
	}
	
	public void closeZKClient() {
		if (client != null) {
			this.client.close();
		}
	}
	
//	public final static String CONFIG_NODE = "/bushro/demo/redis-config";
	public final static String CONFIG_NODE_PATH = "/bushro/demo";
	public final static String SUB_PATH = "/redis-config";
	public static CountDownLatch countDown = new CountDownLatch(1);
	
	public static void main(String[] args) throws Exception {
		Client1 cto = new Client1();
		System.out.println("client1 启动成功...");
		
		final PathChildrenCache childrenCache = new PathChildrenCache(cto.client, CONFIG_NODE_PATH, true);
		childrenCache.start(StartMode.BUILD_INITIAL_CACHE);
		
		// 添加监听事件
		childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
			public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
				// 监听节点变化
				if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
					String configNodePath = event.getData().getPath();
					if (configNodePath.equals(CONFIG_NODE_PATH + SUB_PATH)) {
						System.out.println("监听到配置发生变化,节点路径为:" + configNodePath);
						
						// 读取节点数据
						String jsonConfig = new String(event.getData().getData());
						System.out.println("节点" + CONFIG_NODE_PATH + "的数据为: " + jsonConfig);
						
						// 从json转换配置(转实体类)
						RedisConfig redisConfig = null;
						if (StringUtils.isNotBlank(jsonConfig)) {
							redisConfig = JsonUtils.jsonToPojo(jsonConfig, RedisConfig.class);
						}
						
						// 配置不为空则进行相应操作
						if (redisConfig != null) {
							String type = redisConfig.getType();
							String url = redisConfig.getUrl();
							String remark = redisConfig.getRemark();
							// 判断事件
							if (type.equals("add")) {
								System.out.println("监听到新增的配置,准备下载...");
								// ... 连接ftp服务器,根据url找到相应的配置
								Thread.sleep(500);
								System.out.println("开始下载新的配置文件,下载路径为<" + url + ">");
								// ... 下载配置到你指定的目录
								Thread.sleep(1000);
								System.out.println("下载成功,已经添加到项目中");
								// ... 拷贝文件到项目目录
							} else if (type.equals("update")) {
								System.out.println("监听到更新的配置,准备下载...");
								// ... 连接ftp服务器,根据url找到相应的配置
								Thread.sleep(500);
								System.out.println("开始下载配置文件,下载路径为<" + url + ">");
								// ... 下载配置到你指定的目录
								Thread.sleep(1000);
								System.out.println("下载成功...");
								System.out.println("删除项目中原配置文件...");
								Thread.sleep(100);
								// ... 删除原文件
								System.out.println("拷贝配置文件到项目目录...");
								// ... 拷贝文件到项目目录
							} else if (type.equals("delete")) {
								System.out.println("监听到需要删除配置");
								System.out.println("删除项目中原配置文件...");
							}

						}
					}
				}
			}
		});
		countDown.await();
		cto.closeZKClient();
	}
	
}

acl权限操作与认证授权

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooDefs.Perms;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;

import com.imooc.utils.AclUtils;

public class CuratorAcl {

	public CuratorFramework client = null;
	public static final String zkServerPath = "192.168.254.130:2181";

	public CuratorAcl() {
		RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
		client = CuratorFrameworkFactory.builder().authorization("digest", "bushro1:123456".getBytes())//使用账号密码认证,可以认证多个用户
				.connectString(zkServerPath)
				.sessionTimeoutMs(10000).retryPolicy(retryPolicy)
				.namespace("workspace").build();
		client.start();
	}
	
	public void closeZKClient() {
		if (client != null) {
			this.client.close();
		}
	}
	
	public static void main(String[] args) throws Exception {
		// 实例化
		CuratorAcl cto = new CuratorAcl();
		boolean isZkCuratorStarted = cto.client.isStarted();
		System.out.println("当前客户的状态:" + (isZkCuratorStarted ? "连接中" : "已关闭"));
		
		String nodePath = "/acl/father/child/sub";
		
		List<ACL> acls = new ArrayList<ACL>();
		Id bushro1 = new Id("digest", AclUtils.getDigestUserPwd("bushro1:123456"));
		Id bushro2 = new Id("digest", AclUtils.getDigestUserPwd("bushro2:123456"));
		acls.add(new ACL(Perms.ALL, bushro1));
		acls.add(new ACL(Perms.READ, bushro2));
		acls.add(new ACL(Perms.DELETE | Perms.CREATE, bushro2));
		
		// 创建节点
		byte[] data = "spiderman".getBytes();
		cto.client.create().creatingParentsIfNeeded()//递归方式创建
				.withMode(CreateMode.PERSISTENT)
				.withACL(acls)//该方式只有对最后一个节点设置权限,相应的父节点默认都是"world", "anyone",
				              // 如果后面添加true那么所有创建的节点都是设置的权限
				.forPath(nodePath, data);

		//设置权限
		cto.client.setACL().withACL(acls).forPath("/curatorNode");
		
		// 更新节点数据
		byte[] newData = "batman".getBytes();
		cto.client.setData().withVersion(0).forPath(nodePath, newData);
		
		// 删除节点
		cto.client.delete().guaranteed().deletingChildrenIfNeeded().withVersion(0).forPath(nodePath);
		
		// 读取节点数据
		Stat stat = new Stat();
		byte[] data = cto.client.getData().storingStatIn(stat).forPath(nodePath);
		System.out.println("节点" + nodePath + "的数据为: " + new String(data));
		System.out.println("该节点的版本号为: " + stat.getVersion());
		
		
		cto.closeZKClient();
		boolean isZkCuratorStarted2 = cto.client.isStarted();
		System.out.println("当前客户的状态:" + (isZkCuratorStarted2 ? "连接中" : "已关闭"));
	}
	
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ZooKeeper 之Apache Curator 客户端使用 的相关文章

  • 配置nginx服务器需要修改的配置文件为,01_Nginx安装,nginx下部署项目,nginx.conf配置文件修改,相关文件配置...

    1 下载Nginx 进入Nginx下载地址 http nginx org 2 下载pcre 这个是一个正则表达式的库 Nginx做rewriter的时候回用到这个库 进入pcre的官网 rewrite模式需要pcre http www pc
  • C语言的算法渐进分析

    C语言的基本结构 C语言由头文件组成 在C语言的源代码中有多个源文件 每一个源文件中包含了主函数 库函数以及自动以函数 源程序中可以有多个源文件 但是在运行的过程中只能有一个主函数 并且只能从主函数开始执行 C语言的格式为一行一句 在源程序
  • Android冷启动优化解析,flutter瀑布流列表

    TotalTime 242 WaitTime 288 Complete ThisTime 是指调用过程中最后一个Activity启动时间到这个Activity的 startActivityAndWait调用结束 TotalTime 是指调用
  • 云计算背后的秘密:NoSQL诞生的原因和优缺点

    聊聊为什么NoSQL会在关系型数据库已经非常普及的情况下异军突起 诞生的原因 随着互联网的不断发展 各种类型的应用层出不穷 所以导致在这个云计算的时代 对技术提出了更多的需求 主要体现在下面这四个方面 1 低延迟的读写速度 应用快速地反应能
  • TiDB介绍

    目录 TiDB 简介 一 四大核心应用场景 二 TiDB 整体架构 三 TiDB 数据库的存储 Key Value Pairs 键值对 本地存储 RocksDB Raft 协议 Region MVCC 分布式 ACID 事务 参考 TiDB
  • 002-数据结构之算法的时间复杂度和空间复杂度

    一 概述 对于同一个问题来说 可以有多种解决问题的算法 尽管算法不是唯一的 但是对于问题本身来说相对好的算法还是存在的 这里可能有人会问区分好坏的标准是什么 这个要从 时效 和 存储 两方面来看 好的算法应该具备时效高和存储低的特点 这里的
  • 美团二面:如果每天有百亿流量,你如何保证数据一致性?

    V xin ruyuanhadeng获得600 页原创精品文章汇总PDF 目录 前情提示 什么是数据一致性 一个数据计算链路的梳理 数据计算链路的bug 电商库存数据的不一致问题 大型系统的数据不一致排查有多困难 一 前情提示 这篇文章 咱
  • 顺序查找算法C语言实现

    顺序查找算法 实现思想 静态查找表用顺序存储结构表示时 顺序查找的查找过程为 从表中的最后一个数据元素开始 逐个同记录的关键字做比较 如果匹配成功 则查找成功 反之 如果直到表中第一个关键字查找完也没有成功匹配 则查找失败 应用场景 顺序查
  • SpringBoot-基础-10-自动配置类常用注解

    SpringBoot 基础 10 自动配置类常用注解 一 自动配置类 XXXAutoConfiguration XxxxAutoConfiguration类的含义是 自动配置类 目的是给容器中添加组件 从上示例中 我们可以了解到自动配置类常
  • HTML标题

    目录 HTML 标题 实例 标题很重要 HTML 水平线 实例 HTML 注释以及在PyCharm中快速添加注释 实例 HTML 提示 如何查看源代码 来自本页的实例 HTML 标签参考手册 一个完整的实例 在 HTML 文档中 标题很重要
  • 筛选法与试除法 判断素数

    素数的求解方法 第一种 试除法 第二种 筛选法 试除法 顾名思义 求一个数X是不是素数 就试用小于x大于1区间的自然数 只要有一个能整除 那么x就不是素数 否则就是 以输出100 200之间的素数为例 include
  • 深入理解SD卡基础原理以及内部结构的总结 (转)

    1 简介 SD卡 Secure Digital Memory Card 是一种为满足安全性 容量 性能和使用环境等各方面的需求而设计的一种新型存储器件 SD卡允许在两种模式下工作 即SD模式和SPI模式 本 系统采用SPI模式 本小节仅简要
  • buuctf - web - [极客大挑战 2019]Havefun

    入眼一看 是一只小猫 二话不说 直接F12 根据提示 修改 当前页面 URL 尝试传入参数 直接得flag
  • LWIP-TCP心跳机制

    LWIP TCP心跳机制 简介 在长连接下 可能很长一段时间都没有数据往来 理论上说 这个连接是一直保持连接的 但是实际情况中 如果中间节点出现什么故障是难以知道的 更致命的是 有的节点 防火墙 会自动把一定时间之内没有数据交互的连接给断掉
  • 什么是对网站的base64攻击?

    根据网络安全公司Imperva的一份报告 可以通过Base64编码进行的SQL注入攻击 是最常见的网络应用程序攻击类型之一 占所有攻击的20 这表明 Base64攻击是对网站和网络应用程序的一个重大威胁 Base64是一种常见的编码技术 用

随机推荐

  • 磁盘挂载问题:Fdisk最大只能创建2T分区的盘,超过2T使用parted

    1 下面使用parted工具进行分区的创建 parted dev sdb print 查看分区的使用情况 mklabel gpt 将MBR分区形式转换为GPT分区形式 mkpart promary ext4 划分一个采用ext4文件系统的主
  • SQL SUM() 函数

    SUM 函数返回数值列的总数 SQL SUM 语法 SELECT SUM column name FROM table name WHERE condition column name 是要计算总和的列名 table name 是包含要计算
  • 【学习笔记】感知机模型

    感知机 Perceptron 概述 1957年被提出 是一种有单层计算单元的神经网络模型 在结构上与M P模型相似 提出初衷是解决数据的分类问题 感知机是神经网络和支持向量机的基础 感知机原理 感知机本身是一种能进行二分类的线性模型 只要被
  • mysql为什么使用b+树

    MySQL 使用 B 树有以下几个原因 查询效率高 B 树的查询时间复杂度是 log n 级别的 相比链表和二叉树的 O n 性能要高得多 支持范围查询 B 树能够支持范围查询 这在 MySQL 中经常用于 WHERE 子句中的 BETWE
  • HC-05蓝牙模块使用记录

    前言 后面可能需要用到蓝牙远程控制 所以提前了解了一下 主要是用买来的蓝牙模块HC 05 主要包括一个蓝牙芯片CSR BC417 该公司是剑桥的一个公司 现已被高通收购 和一个FLASH芯片 调试一下两个HC 05之间基本的通讯以及与手机蓝
  • 关于TypeScript的引用类型

    基本数据类型 引用数据类型 赋值引用 public copyCite let obj name 1 let copyObj obj obj name 2 console log copyObj name 2 由于对象之间的赋值是复制了地址
  • 位运算的应用

    前天几天研究了下JDK的Collection接口 本来准备接着研究Map接口 可是一查看HashMap类源码傻眼咯 到处是位运算实现 所以我觉得还是有必要先补补位运算知识 不然代码看起来有点费力 今天系统研究了下 现记录如下 首先要明白一个
  • elementUI的el-table表格不生效问题

    我之前下载的elementUI依赖是用的镜像cnpm 删掉原来的依赖重新下npm的依赖npm i element ui S 重启前台服务就可以了
  • vue3和vite

    1 安装 vue cli 3 yarn add vue cli next 2 安装vite vue add vite 3 安装成功后package json中会添加 scripts vite node bin vite devDepende
  • 【hello C++】智能指针

    目录 一 内存泄漏 1 1 什么是内存泄漏 内存泄漏的危害 1 2 内存泄漏分类 1 3 如何检测内存泄漏 1 4 如何避免内存泄漏 二 智能指针的使用及原理 2 1 RAII 2 2 智能指针的原理 2 3 智能指针的发展历程 2 4 智
  • componentDidUpdate vs componentWillReceiveProps

    componentDidUpdate有两个参数prevProps和prevState 不管是父组件props的修改还是state状态的更改都会触发该方法 而componentWillReceiveProps只有在父组件重新render pr
  • IDEA 2020.1官网汉化插件安装

    idea 终于更新了2020 1版本 推荐使用2020的版本 新增了好多的特性 官方也终于支持了中文语言包 但是有些兄弟下载后在插件市场无法找到官方的汉化包等问题 请安装下面操作即可 1 去IDEA插件中心 https plugins je
  • protobuf通信消息设计技巧备忘

    1 有一个全局的ProtobufMessage 所有的requestXXX responseXXX都作为他的一个可选属性 这样简单粗暴的避免了需要二次序列化反序列化的恶心问题 2 有一个CommonMessage作为他的一个字段 用来存放公
  • Data-centric Artificial Intelligence: A Survey

    本文是AI相关的论文 针对 Data centric Artificial Intelligence A Survey 的翻译 以数据为中心的人工智能 综述 摘要 1 引言 2 数据为中心AI的背景 3 训练数据开发 4 推理数据开发 5
  • 逻辑地址空间、页表与如何确定页表项大小

    32位逻辑地址空间 一页4KB 按字节编制 页式内存管理中如何确定页表项大小 因为是32位逻辑地址 故寻址空间为2 32B 而一页大小为4KB 故需要2 32 4B 2 20页 1M页 假设在内存中地址 而页表则是对这些页表的记录 因一页大
  • lastpass 右边_如何使用LastPass的替代产品Bitwarden管理密码

    lastpass 右边 您是否觉得自己拥有的密码超出了跟踪范围 这可能不仅仅是一种感觉 像我们大多数人一样 您可能很难记住所有这些密码 无论它们多么简单或复杂 许多人使用诸如LastPass和1Password之类的流行服务来帮助他们弄乱密
  • ARMv7体系结构汇总

    文章目录 1 处理器工作模式 2 处理器工作状态 3 ARM寄存器 3 1 通用寄存器 3 2 状态寄存器 3 3 备份的程序状态寄存器SPSR 3 4 Thumb寄存器 4 ARM指令系统 4 1 指令和指令格式 4 2 指令的可选后缀
  • 科大个人主页/FTP系统

    参考网页 https ustcnet ustc edu cn 2015 0324 c11130a120792 page htm 最终结果如下 大家快来逛逛吧 http home ustc edu cn sa517486
  • linux系统下从/proc中找回误删除的控制文件

    linux系统下从 proc中找回误删除的控制文件 SYS PROD3 gt select name from v controlfile NAME home oracle db1 control01 ctl SYS PROD3 gt rm
  • ZooKeeper 之Apache Curator 客户端使用

    ZooKeeper 原生不足之处 超时重连 不支持自动 需要手动操作 Watch注册一次后会失效 不支持递归创建节点 Apache Curator apache的开源项目 解决watcher注册一次就失效的问题 api更加简单易用 提供更多