这一节我们主要来看一下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. unity探索者之微信分享回调

    版权声明:本文为原创文章,转载请声明http://www.cnblogs.com/unityExplorer/p/7574561.html 上一遍讲了微信分享的一些坑,然后就忘了回调这事儿了,今天补上 ...

  2. Goland远程连接Linux开发调试

    参考链接: https://blog.csdn.net/huwh_/article/details/77879152?utm_source=blogxgwz3 https://baijiahao.ba ...

  3. 手把手教Linux驱动3-之字符设备架构详解,有这篇就够了

    一.Linux设备分类 Linux系统为了管理方便,将设备分成三种基本类型: 字符设备 块设备 网络设备 字符设备: 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程 ...

  4. 怎么创建一个良好的Git提交信息

    译   原文:https://dev.to/chrissiemhrk/git-commit-message-5e21 提交信息是对提交之前添加和更改的文件所做的更改的简短描述. 良好的提交信息不仅对你 ...

  5. GPU虚拟机创建时间深度优化

    ​桔妹导读:GPU虚拟机实例创建速度慢是公有云面临的普遍问题,由于通常情况下创建虚拟机属于低频操作而未引起业界的重视,实际生产中还是存在对GPU实例创建时间有苛刻要求的业务场景.本文将介绍滴滴云在解决 ...

  6. 简述BFS与DFS

    简述BFS与DFS 最近学习了数据结构课程以及应对蓝桥杯备考,所以花费了一点时间将比较重要的两个搜索BFS(宽度优先搜索)和DFS(深度优先搜索)大致思路以及代码整理出来,如有错误,还请各位大佬批评改 ...

  7. 8点了解Java服务端单元测试

    一. 前言 单元测试并不只是为了验证你当前所写的代码是否存在问题,更为重要的是它可以很大程度的保障日后因业务变更.修复Bug或重构等引起的代码变更而导致(或新增)的风险. 同时将单元测试提前到编写正式 ...

  8. NGINX 命令 重启 WINDOWS

    最近系统更新比较频繁,web系统老是上新,因此在nginx这边经常需要重启或者刷新,做了一个批命令供参考. 1.鼠标右键-新建-一个.TXT文本文档:在里面输入NGINX重启的命令. 2.输入NGIN ...

  9. CodeForces - 1114D-Flood Fill (区间dp)

    You are given a line of nn colored squares in a row, numbered from 11 to nn from left to right. The  ...

  10. google protocol buffer——protobuf的问题及改进一

    这一系列文章主要是对protocol buffer这种编码格式的使用方式.特点.使用技巧进行说明,并在原生protobuf的基础上进行扩展和优化,使得它能更好地为我们服务. 在上一篇文章中,我们完整了 ...