zk 文件存储
zk 有 2 种文件,快照和事务日志,快照是某一时刻的全量数据,事务日志中记录了数据的修改事件。
快照的文件名是 snapshot.zxid,zxid 是当前最大的事务 id
// org.apache.zookeeper.server.persistence.FileTxnSnapLog#save
public void save(DataTree dataTree,
ConcurrentHashMap<Long, Integer> sessionsWithTimeouts)
throws IOException {
long lastZxid = dataTree.lastProcessedZxid;
// 快照文件名为 snapshot.lastZxid
File snapshotFile = new File(snapDir, Util.makeSnapshotName(lastZxid));
LOG.info("Snapshotting: 0x{} to {}", Long.toHexString(lastZxid),
snapshotFile);
snapLog.serialize(dataTree, sessionsWithTimeouts, snapshotFile); }
事务日志的文件名是 log.zxid,zxid 是当前文件第一条日志的事务 id
// org.apache.zookeeper.server.persistence.FileTxnLog#append
public synchronized boolean append(TxnHeader hdr, Record txn)
throws IOException
{
if (hdr == null) {
return false;
} if (hdr.getZxid() <= lastZxidSeen) {
LOG.warn("Current zxid " + hdr.getZxid()
+ " is <= " + lastZxidSeen + " for "
+ hdr.getType());
} else {
lastZxidSeen = hdr.getZxid();
} if (logStream==null) {
if(LOG.isInfoEnabled()){
LOG.info("Creating new log file: " + Util.makeLogName(hdr.getZxid()));
}
// 创建一个新的事务日志文件 log.zxid,这里的 zxid 是第一条事务日志的 zxid
logFileWrite = new File(logDir, Util.makeLogName(hdr.getZxid()));
fos = new FileOutputStream(logFileWrite);
logStream=new BufferedOutputStream(fos);
oa = BinaryOutputArchive.getArchive(logStream);
FileHeader fhdr = new FileHeader(TXNLOG_MAGIC,VERSION, dbId);
fhdr.serialize(oa, "fileheader");
// Make sure that the magic number is written before padding.
logStream.flush();
filePadding.setCurrentSize(fos.getChannel().position());
streamsToFlush.add(fos);
}
filePadding.padFile(fos.getChannel());
byte[] buf = Util.marshallTxnEntry(hdr, txn);
if (buf == null || buf.length == 0) {
throw new IOException("Faulty serialization for header " +
"and txn");
}
Checksum crc = makeChecksumAlgorithm();
crc.update(buf, 0, buf.length);
oa.writeLong(crc.getValue(), "txnEntryCRC");
Util.writeTxnBytes(oa, buf); return true;
}
zk 加载数据:从 snap 文件和 log 文件解析出全量数据
// org.apache.zookeeper.server.persistence.FileTxnSnapLog#restore
public long restore(DataTree dt, Map<Long, Integer> sessions,
PlayBackListener listener) throws IOException {
snapLog.deserialize(dt, sessions);
return fastForwardFromEdits(dt, sessions, listener);
}
逆序选择 100 个 snap 文件,从最新的文件开始解析,如果有一个文件校验正确,则退出
public long deserialize(DataTree dt, Map<Long, Integer> sessions)
throws IOException {
// we run through 100 snapshots (not all of them)
// if we cannot get it running within 100 snapshots
// we should give up
List<File> snapList = findNValidSnapshots(100);
if (snapList.size() == 0) {
return -1L;
}
File snap = null;
boolean foundValid = false;
for (int i = 0; i < snapList.size(); i++) {
snap = snapList.get(i);
InputStream snapIS = null;
CheckedInputStream crcIn = null;
try {
LOG.info("Reading snapshot " + snap);
snapIS = new BufferedInputStream(new FileInputStream(snap));
crcIn = new CheckedInputStream(snapIS, new Adler32());
InputArchive ia = BinaryInputArchive.getArchive(crcIn);
deserialize(dt, sessions, ia);
long checkSum = crcIn.getChecksum().getValue();
long val = ia.readLong("val");
if (val != checkSum) {
throw new IOException("CRC corruption in snapshot : " + snap);
}
foundValid = true;
break;
} catch(IOException e) {
LOG.warn("problem reading snap file " + snap, e);
} finally {
if (snapIS != null)
snapIS.close();
if (crcIn != null)
crcIn.close();
}
}
if (!foundValid) {
throw new IOException("Not able to find valid snapshots in " + snapDir);
}
dt.lastProcessedZxid = Util.getZxidFromName(snap.getName(), SNAPSHOT_FILE_PREFIX);
return dt.lastProcessedZxid;
}
对比已经解析出的最大 zxid,选择对应的 log 文件
// org.apache.zookeeper.server.persistence.FileTxnLog.FileTxnIterator#init
void init() throws IOException {
storedFiles = new ArrayList<File>();
List<File> files = Util.sortDataDir(FileTxnLog.getLogFiles(logDir.listFiles(), 0), LOG_FILE_PREFIX, false);
for (File f: files) {
if (Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX) >= zxid) {
storedFiles.add(f);
}
// add the last logfile that is less than the zxid
else if (Util.getZxidFromName(f.getName(), LOG_FILE_PREFIX) < zxid) {
storedFiles.add(f);
break;
}
}
goToNextLog();
if (!next())
return;
while (hdr.getZxid() < zxid) {
if (!next())
return;
}
}
zk 文件存储的更多相关文章
- Kafka与RocketMq文件存储机制对比
一个商业化消息队列的性能好坏,其文件存储机制设计是衡量一个消息队列服务技术水平和最关键指标之一. 开头问题 kafka文件结构和rocketMQ文件结构是什么样子?特点是什么? 一.目录结构 Kafk ...
- Android数据存储之Android 6.0运行时权限下文件存储的思考
前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...
- 深入理解Sqlserver文件存储之页和应用 (转)
我们每天都在使用数据库,我们部门使用最多的关系数据库有Sqlserver,Oracle,有没有想过这些数据库是怎么存放到操作系统的文件中的?有时候为了能够设计出最优的表结构,写出高性能的Sqlserv ...
- app端上传文件至服务器后台,web端上传文件存储到服务器
1.android前端发送服务器请求 在spring-mvc.xml 将过滤屏蔽(如果不屏蔽 ,文件流为空) <!-- <bean id="multipartResolver&q ...
- MongoDb gridfs-ngnix文件存储方案
在各类系统应用服务端开发中,我们经常会遇到文件存储的问题. 常见的磁盘文件系统,DBMS传统文件流存储.今天我们看一下基于NoSQL数据库MongoDb的存储方案.笔者环境 以CentOS ...
- Hadoop中pid文件存储
我的hadoop集群部署在自己电脑虚拟机上,有时候我是挂起虚拟机,第二天再打开发现有些线程就挂了,比如namenode,好奇怪,当时看了一些帖子说是和pid存储有关,找到log看到找不到pid.因为基 ...
- Android文件存储
文件存储是Android中最基本的一种数据存储方式,它不读存储的内容进行任何的格式化处理,所有数据原封不动的保存在文件之中.如果想用文件存储的方式保存一些较为复杂的数据,就需要定义一套自己的格式规范, ...
- Kafka深入理解-1:Kafka高效的文件存储设计
文章摘自:美团点评技术团队 Kafka文件存储机制那些事 Kafka是什么 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日 ...
- .Net平台下,分布式文件存储的实现
遇到的问题 对于Web程序,使用一台服务器的时候,客户端上传的文件一般也都是存储在这台服务器上.但在集群环境中就行不通了,如果每个服务器都存储自己接受到的文件,就乱套了,数据库中明明有这个附件的记录, ...
随机推荐
- CPP标准模板库 随笔
对于无序容器而言,其次序是不固定的,就算添加一个元素,也可能全盘改变次序.唯一可以保证的是,内容相同的元素会相邻.(eg: 23,1,1,25,3,27,5,7,11,11) 迭代器的种类: 1,前向 ...
- c++ 指定目录下的文件遍历
要实现指定目录下文件的遍历需要执行一下的部分: 第一步获取当前路径的名字:(MAX_PATH是在windows定义的所有的路径名字不超过其,调用该函数会使得得到当前的目录) #include < ...
- 六、取消eslint 校验代码
一.取消eslint 校验代码 删除 "eslintConfig": { "root": true, "env": { "node ...
- Centos 7搭建Gitlab服务器以及操作(创建项目,创建群组,创建用户,添加密钥)
一. 安装并配置依赖包 在CentOS系统上安装所需的依赖:ssh,防火墙,postfix(用于邮件通知) ,wget,以下这些命令也会打开 系统防火墙中的HTTP和SSH端口访问 安装前准备 命令: ...
- 高性能mysql 第1章 mysql架构与历史
mysql逻辑架构图: 第一层 客户端 第二层(服务层):针对所有类型的存储引擎可以公共提取的部分.将存储引擎抽离之后的其他部分都在这里.如:查询解析,分析优化,内置函数,存储过程,触发器,视图. 第 ...
- package+explorer不显示项目的问题
昨天遇到了这个问题,百度了一下,怎么搞的都有,但是感觉都不理想,晚上的时候才在网上又发现这个方法,今天试了一下,效果还不错,分享一下. 点击 Window ---> Close All Pers ...
- MyEclipse使用教程:添加和更新插件(二)
[MyEclipse CI 2019.4.0安装包下载] 通过Eclipse Marketplace目录或各种更新站点类型添加插件来自定义您的Genuitec IDE. Genuitec提供以下IDE ...
- ssh转发流量的四种姿势
在很多时候拿到了内网的一台主机,我们需要用它做跳板来对内网进一步扩大战果. 也许方法很多,meterpreter,nc等等.但是最方便也最有可能穿透防火墙的方法,就是用ssh. 分为四种类型: 本地转 ...
- C# 常用方法——图片转base64字符串
其他扩展方法详见:https://www.cnblogs.com/zhuanjiao/p/12060937.html /// <summary> /// Image 转成 base64 / ...
- CSS currentColor 变量
㈠currentColor定义及理解 来自MDN的解释:currentColor代表了当前元素被应用上的color颜色值. 使用它可以将当前这个颜色值应用到其他属性上,或者嵌套元素的其他属性上. 你这 ...