这一节我们主要来看一下zookeeper文件系统的实现。

树结构

  为了提高对指定节点的操作,zookeeper使用一个HashMap来存储树结构数据,key为数据路径,value为节点数据。

树节点(DataNode)

 public class DataNode implements Record {
//父节点
DataNode parent;
//节点数据
byte data[];
//节点权限
Long acl;
//节点状态信息
public StatPersisted stat;
//子节点名
private Set<String> children = null; }

数节点状态(StatPersisted)

 public class StatPersisted implements Record {
//该节点创建是的事务xid
private long czxid;
//该节点最后一次修改的事务id
private long mzxid;
//创建时间
private long ctime;
//最后一次修改时间
private long mtime;
//节点版本号
private int version;
//子节点版本号
private int cversion;
//acl版本号
private int aversion;
//是否为零时节点
private long ephemeralOwner;
//子列表被修改的zxid
private long pzxid;
}

配额管理

  zookeeper在创建、修改节点时可以设置特定路径上的配额。在实现上,配额也存储在文件系统中,并且还存储了节点当前的信息。配额的控制在特定的路径下:/zookeeper/quota/{节点路径}/zookeeper_limits 节点的限制数据节点;/zookeeper/quota/{节点路径}/zookeeper_stats  节点的当前量节点。一个节点路径中只能有一个配额限制。

  当在对某个节点进行操作时,我们需要知道该路径下的哪个节点设置了配额,因为树结构使用hashmap来存储,所以不便于通过路径查找,所以使用了一个树结构来表示那个节点上配置了限额。

配额路径(PathTrie)

 public class PathTrie {
//根节点
private final TrieNode rootNode ;
//节点
static class TrieNode {
//是否设置配额,false没有,true有
boolean property = false;
//子节点
final HashMap<String, TrieNode> children;
//父节点
TrieNode parent = null; //删除子节点配额
void deleteChild(String childName) {
synchronized(children) {
if (!children.containsKey(childName)) {
return;
}
TrieNode childNode = children.get(childName);
//如果子节点没有自己点直接删除,否则设置property为false
if (childNode.getChildren().length == 1) {
childNode.setParent(null);
children.remove(childName);
}
else {
childNode.setProperty(false);
}
}
}
}
//新增配额节点
public void addPath(String path) {
if (path == null) {
return;
}
String[] pathComponents = path.split("/");
TrieNode parent = rootNode;
String part = null;
if (pathComponents.length <= 1) {
throw new IllegalArgumentException("Invalid path " + path);
}
for (int i=1; i<pathComponents.length; i++) {
part = pathComponents[i];
if (parent.getChild(part) == null) {
parent.addChild(part, new TrieNode(parent));
}
parent = parent.getChild(part);
}
parent.setProperty(true);
} //删除配额节点
public void deletePath(String path) {
if (path == null) {
return;
}
String[] pathComponents = path.split("/");
TrieNode parent = rootNode;
String part = null;
if (pathComponents.length <= 1) {
throw new IllegalArgumentException("Invalid path " + path);
}
for (int i=1; i<pathComponents.length; i++) {
part = pathComponents[i];
if (parent.getChild(part) == null) {
return;
}
parent = parent.getChild(part);
}
TrieNode realParent = parent.getParent();
realParent.deleteChild(part);
} //获取指定路径上配额节点最大路径
public String findMaxPrefix(String path) {
if (path == null) {
return null;
}
if ("/".equals(path)) {
return path;
}
String[] pathComponents = path.split("/");
TrieNode parent = rootNode;
List<String> components = new ArrayList<String>();
if (pathComponents.length <= 1) {
throw new IllegalArgumentException("Invalid path " + path);
}
int i = 1;
String part = null;
StringBuilder sb = new StringBuilder();
//最大路径的index
int lastindex = -1;
while((i < pathComponents.length)) {
if (parent.getChild(pathComponents[i]) != null) {
part = pathComponents[i];
parent = parent.getChild(part);
components.add(part);
if (parent.getProperty()) {
lastindex = i-1;
}
}
else {
break;
}
i++;
}
for (int j=0; j< (lastindex+1); j++) {
sb.append("/" + components.get(j));
}
return sb.toString();
}
}

监听器管理

  zookeeper可以对指定路径进行监听,当指定路径发生变化时,监听器会执行响应的动作。主要是通过将path和watcher建立关联关系,在对指定路径进行操作是调用相应监听器方法。

监听管理器(WatchManager)

 public class WatchManager {
//key为path value为该path对应的watcher集合
private final HashMap<String, HashSet<Watcher>> watchTable =
new HashMap<String, HashSet<Watcher>>();
//key为watcher value为该watcher对应的path集合,使用两个hashmap来维护路径和监听器是因为watcher和路径是多对多关系,这样无论通过watcher还是路径都可以很快找到对应的路径和watcher。
private final HashMap<Watcher, HashSet<String>> watch2Paths =
new HashMap<Watcher, HashSet<String>>(); public synchronized void addWatch(String path, Watcher watcher) {
//新增watcher到watchTable
HashSet<Watcher> list = watchTable.get(path);
if (list == null) {
list = new HashSet<Watcher>(4);
watchTable.put(path, list);
}
list.add(watcher);
//新增watcher到watch2Paths
HashSet<String> paths = watch2Paths.get(watcher);
if (paths == null) {
paths = new HashSet<String>();
watch2Paths.put(watcher, paths);
}
paths.add(path);
} public synchronized void removeWatcher(Watcher watcher) {
//从watch2Paths和watchTable删除watcher
HashSet<String> paths = watch2Paths.remove(watcher);
if (paths == null) {
return;
}
for (String p : paths) {
HashSet<Watcher> list = watchTable.get(p);
if (list != null) {
list.remove(watcher);
if (list.size() == 0) {
watchTable.remove(p);
}
}
}
}
//触发watcher
public Set<Watcher> triggerWatch(String path, EventType type, Set<Watcher> supress) {
WatchedEvent e = new WatchedEvent(type,
KeeperState.SyncConnected, path);
HashSet<Watcher> watchers;
synchronized (this) {
//zookeeper的通知是一次性的,也就是说如果一个路径触发通知后,相应的watcher会从这两个hashmap中删除。
watchers = watchTable.remove(path);
for (Watcher w : watchers) {
HashSet<String> paths = watch2Paths.get(w);
if (paths != null) {
paths.remove(path);
}
}
}
for (Watcher w : watchers) {
if (supress != null && supress.contains(w)) {
continue;
}
w.process(e);
}
return watchers;
}
}

临时节点

  zookeeper中有一类节点在创建的session结束后会被清除掉,zookeeper在创建这些节点时会记录节点和session 的对应关系,到session结束是,删除这些节点。

结束session(DataTree.killSession)

 //session与零时节点对应关系
private final Map<Long, HashSet<String>> ephemerals =
new ConcurrentHashMap<Long, HashSet<String>>();
//关闭session
void killSession(long session, long zxid) {
//session结束后,删除零时节点
HashSet<String> list = ephemerals.remove(session);
if (list != null) {
for (String path : list) {
try {
deleteNode(path, zxid);
} catch (NoNodeException e) {
LOG.warn("Ignoring NoNodeException for path " + path
+ " while removing ephemeral for dead session 0x"
+ Long.toHexString(session));
}
}
}
}

权限管理

  zookeeper的每个节点都会存储该节点可以访问的用户已经可以执行的操作。

权限(ACL)

 public class ACL implements Record {
//perms即权限,有五种权限:READ(可读);WRITE(可写);CREATE(可创建子节点);DELETE(可删除子节点);ADMIN(管理权限);perms的每一位代表一种权限。
private int perms;
//id是授权的对象。
private org.apache.zookeeper.data.Id id;
}
public class Id implements Record {
//scheme是权限模式,有五种模式:digest(通过用户名密码,id为user:password);auth();ip(通过ip,id为ip地址);world(固定用户为anyone,为所有Client端开放权限 );super(对应的id拥有超级权限)。
private String scheme;
private String id;
}

每个节点可以设置多个权限,实际节点权限只存储一个整数,对应的acl信息保存在两个hashmap中。(DataTree.java)

 public final Map<Long, List<ACL>> longKeyMap = new HashMap<Long, List<ACL>>();
public final Map<List<ACL>, Long> aclKeyMap = new HashMap<List<ACL>, Long>();

节点操作

												

zookeeper(2) 文件系统的更多相关文章

  1. Hadoop学习笔记—14.ZooKeeper环境搭建

    从字面上来看,ZooKeeper表示动物园管理员,这是一个十分奇妙的名字,我们又想起了Hadoop生态系统中,许多项目的Logo都采用了动物,比如Hadoop采用了大象的形象,所以我们可以猜测ZooK ...

  2. zookeeper能做什么?

    Zookeeper是Hadoop的一个子项目,虽然源自hadoop,但是我发现zookeeper脱离hadoop的范畴开发分布式框架的运用越来越多.今天我想谈谈zookeeper,本文不谈如何使用zo ...

  3. Zookeeper的功能以及工作原理

    1.ZooKeeper是什么?ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的 ...

  4. zookeeper系列之六—zookeeper之应用

    http://www.cnblogs.com/sharpxiajun/archive/2013/06/02/3113923.html Zookeeper是hadoop的一个子项目,虽然源自hadoop ...

  5. 分布式服务框架:Zookeeper

    Zookeeper是一个高性能,分布式的,开源分布式应用协调服务.它提供了简单原始的功能,分布式应用可以基于它实现更高级的服务,比如同步,配置管理,集群管理,名空间.它被设计为易于编程,使用文件系统目 ...

  6. 分布式网站架构后续:zookeeper技术浅析

    Zookeeper是hadoop的一个子项目,虽然源自hadoop,但是我发现zookeeper脱离hadoop的范畴开发分布式框架的运用 越来越多.今天我想谈谈zookeeper,本文不谈如何使用z ...

  7. 七:zookeeper与paxos的分析

    zookeeper是什么 官方说辞:Zookeeper 分布式服务框架是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务 ...

  8. zookeeper入门必读

    (如果感觉有帮助,请帮忙点推荐,添加关注,谢谢!你的支持是我不断更新文章的动力.本博客会逐步推出一系列的关于大型网站架构.分布式应用.设计模式.架构模式等方面的系列文章) 今天我想谈谈zookeepe ...

  9. zookeeper使用场景【转】

    分布式网站架构后续:zookeeper技术浅析   Zookeeper是hadoop的一个子项目,虽然源自hadoop,但是我发现zookeeper脱离hadoop的范畴开发分布式框架的运用越来越多. ...

随机推荐

  1. 笔记:Windows Server2008R2服务安装

    Windows Server2008R2 服务安装 服务一:IIS,internet information services,互联网信息服务,微软开发的运行在Windows系统中互联网服务,提供了w ...

  2. Latex — 写作编译过程中遇到问题记录与总结

    最近在训练的时候,又开始用Latex进行写作.碰到了很多问题,将问题进行记录与总结. 一.输出中文的问题 由于写作的时候用的是中文,而之前用的是英文,故碰到的第一个问题就是中文的问题.我之前下的是Wi ...

  3. RedHat 6.8 离线安装Docker (rpm包安装)

    我的环境: [root@localhost ~]# uname -r 2.6.32-642.el6.x86_64 [root@localhost ~]# cat /etc/redhat-release ...

  4. 高并发&性能优化(一)------总体介绍

    [开篇词] 本文主要通过一些经典的高并发场景,以及一些基本的运维工具来讲述一些关于高并发以及性能优化相关的内容,主要包括性能瓶颈的定位,性能调优的思路和技巧等. [性能的衡量指标] ?什么是性能 性能 ...

  5. W3C标准和语义化

    一.语义化的理解 根据内容选择合适的标签,便于开发者阅读,在写出更优雅的代码的同时让浏览器很好的解析. 目的 1.在没有CSS的情况下,页面也能呈现出很好的内容结构和代码结构: 2.有利于SEO:和搜 ...

  6. java23种设计模式——八、组合模式

    目录 java23种设计模式-- 一.设计模式介绍 java23种设计模式-- 二.单例模式 java23种设计模式--三.工厂模式 java23种设计模式--四.原型模式 java23种设计模式-- ...

  7. C++ int与char[]的相互转换

    C++ int与char[]的相互转换 一.itoa函数与atio函数①把int类型数字转成char类型,可以使用itoa函数. itoa函数原型: char*itoa(int value,char* ...

  8. 深入了解v-model流程

    v-model原理 vue中v-model是一个语法糖,所谓的语法糖就是对其他基础功能的二次封装而产生的功能.简单点说,v-model本身就是父组件对子组件状态以及状态改变事件的封装.其实现原理上分为 ...

  9. Mybatis入门篇之基础CRUD

    前言 作为一个资深后端码农天天都要和数据库打交道,最早使用的是 Hiberate,一个封装性极强的持久性框架.自从接触到 Mybatis 就被它的灵活性所折服了,可以自己写 SQL,虽然轻量级,但是麻 ...

  10. lua 优化

    彻底解析Android缓存机制——LruCache https://www.jianshu.com/p/b49a111147ee lua:部分常用操作的效率对比及代码优化建议(附测试代码) https ...